Skip to content

fix(marketplace): retry failed agreement events instead of dropping them - #195

Merged
stewartjarod merged 1 commit into
polylane/autofix/xs41wzfia9d7from
fix/marketplace-retry-failed-records
Oct 19, 2026
Merged

stewartjarod merged 1 commit into
polylane/autofix/xs41wzfia9d7from
fix/marketplace-retry-failed-records

Conversation

@stewartjarod

Copy link
Copy Markdown
Contributor

Stacked on #189. Merge that first; this PR then retargets to main.

Problem

marketplace-events caught every per-record error, sent it to Sentry, and returned success, so SQS deleted the message. A transient failure (a dropped DB connection, say) on an activation event was never retried and never dead-lettered. The buyer stayed pending, and the DLQ consumer added in #189 never saw it. Only Lambda-level failures (timeouts, crashes) reached the DLQ.

Change

The handler now reports each failed record as a batch item failure and still never throws. partialResponses: true is already set on the subscription in infra/marketplace.ts, so no infra change is needed. SQS retries just the failed record. After 3 tries it goes to MarketplaceEventsDlq, where #189's consumer marks a still-pending subscription failed.

Retrying is safe because every write is idempotent under redelivery: the status update is guarded on the event timestamp, and the welcome email on its conditional claim.

Malformed JSON is reported too. It will fail all 3 tries and land in the DLQ, which logs it. That costs two extra no-op invocations and keeps one path for every failure.

Tests

  • Malformed record → batchItemFailures: [m-bad] (replaces the "swallows" test)
  • Batch with one failing record → only that record is reported, and the other still applies
  • Clean batch → batchItemFailures: []

🤖 Generated with Claude Code

https://claude.ai/code/session_014QZmHPbcx2nhuuDHy86YQ2

The worker caught every per-record error, logged it, and returned success,
so SQS deleted the message. A transient database error on an activation
never reached the retries or the dead-letter queue, and the buyer stayed
pending. Report failed records as batch item failures (partialResponses is
already on) so SQS retries just those and dead-letters them once spent.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014QZmHPbcx2nhuuDHy86YQ2
@vercel

vercel Bot commented Oct 19, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

2 Skipped Deployments
Project Deployment Actions Updated
wraps-web Skipped Skipped Oct 19, 2026 3:26am UTC
wraps-website Skipped Skipped Oct 19, 2026 3:26am UTC

Request Review

@vercel
vercel Bot temporarily deployed to Preview – wraps-web October 19, 2026 03:26 Inactive
@vercel
vercel Bot temporarily deployed to Preview – wraps-website October 19, 2026 03:26 Inactive
@stewartjarod
stewartjarod merged commit a985eb8 into polylane/autofix/xs41wzfia9d7 Oct 19, 2026
4 checks passed
@stewartjarod
stewartjarod deleted the fix/marketplace-retry-failed-records branch October 19, 2026 05:37
stewartjarod added a commit that referenced this pull request Oct 19, 2026
* fix(marketplace): subscribe a consumer to the agreement-event dead-letter queue

Co-authored-by: polylane[bot] <277585245+polylane[bot]@users.noreply.github.com>

* fix(marketplace): only fail a still-pending subscription from the DLQ

The main worker swallows per-record errors, so what dead-letters is a whole
batch whose Lambda timed out or crashed. Records earlier in that batch may
already have been applied, and failing them would mark a live subscription
failed. Guard the update on status = pending and surface settled rows to
Sentry without touching them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014QZmHPbcx2nhuuDHy86YQ2

* fix(marketplace): retry failed agreement events instead of dropping them (#195)

The worker caught every per-record error, logged it, and returned success,
so SQS deleted the message. A transient database error on an activation
never reached the retries or the dead-letter queue, and the buyer stayed
pending. Report failed records as batch item failures (partialResponses is
already on) so SQS retries just those and dead-letters them once spent.


Claude-Session: https://claude.ai/code/session_014QZmHPbcx2nhuuDHy86YQ2

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Jarod Stewart <949393+stewartjarod@users.noreply.github.com>
Co-authored-by: polylane[bot] <277585245+polylane[bot]@users.noreply.github.com>
Co-authored-by: stewartjarod <stewartjarod@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Jarod Stewart <jarod@wraps.dev>

This branch was previously deployed

2 inactive deployments
Preview – wraps-web — 85dd854b Deployed Oct 19, 2026 by vercel[bot]
Preview – wraps-website — 85dd854b Deployed Oct 19, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant