Skip to content

fix: mark runs failed when the SQS send fails instead of leaving them queued - #19

Merged
DHYEY166 merged 2 commits into
mainfrom
fix/fail-run-on-queue-send-error
Oct 3, 2026
Merged

DHYEY166 merged 2 commits into
mainfrom
fix/fail-run-on-queue-send-error

Conversation

@DHYEY166

@DHYEY166 DHYEY166 commented Oct 3, 2026

Copy link
Copy Markdown
Owner

What

When SendMessage fails after a route has moved a run forward, the route now marks the run failed with a clear error_message and returns 503 { error, run_status: "failed" }. It no longer leaves the run stuck.

Route Queue Status before the send Before this PR on send failure
POST /api/approve-rules executor (SQS_QUEUE_URL) queued logged, 200, stuck in queued
POST /api/auto-validate/[runId] executor queued logged, 200, stuck in queued
POST /api/webhooks/profile-complete (when AI_QUEUE_ENABLED=true) AI jobs awaiting_ai unhandled 500, stuck in awaiting_ai

The shared helper is src/lib/queue-failure.ts. The review page already shows the response's error, and the run page shows error_message on failed runs.

Look hardest at

  • The UPDATE is conditional (WHERE id = $1 AND status = <status the route set>). SendMessage can fail even though SQS accepted the message, for example on a timeout. If the executor has already claimed the run, it is left alone. If the run was marked failed first, the executor's own conditional claim skips it. The helper never throws: if the DB update fails, the route still returns 503, and reconcile-runs remains the backstop.
  • suggest-transforms called auto-validate and, on any non-2xx, overwrote error_message with auto-validate error 503: …. That UPDATE now skips runs that are already failed, so the clearer message survives.

Tests

  • Unit tests: approve-rules/route.test.ts (extended, including a DB failure while marking the run failed), plus new auto-validate/[runId]/route.test.ts and webhooks/profile-complete/route.test.ts.
  • Integration: approve-rules-claim.test.ts sends to a LocalStack queue that doesn't exist, so the SendMessage error is real, and asserts the run is failed with the message.
  • Locally: eslint, tsc, vitest (241 passed) and the integration suite (26 passed).

After merge

This is an app-only change, so Vercel's deploy on merge is enough. Docs: the runbook row and the README limitation are updated.

… queued

approve-rules and auto-validate move a run to 'queued' and then send to the
executor queue; profile-complete moves it to 'awaiting_ai' and sends to the
AI jobs queue. When SendMessage failed, approve-rules and auto-validate only
logged and returned 200, and profile-complete threw a bare 500. Either way
the run sat in its in-between status with no message until reconcile-runs
failed it 20 minutes later.

Now each route marks the run failed with a message the run page shows and
returns 503 { error, run_status: 'failed' }. The shared helper
(src/lib/queue-failure.ts) updates only if the run is still in the status
the route set, because SendMessage can fail after SQS accepted the message
and a worker may already have claimed the run. suggest-transforms no longer
overwrites that message with 'auto-validate error 503: ...'.

Tests: unit tests for all three routes, and an integration test that sends
to a LocalStack queue that does not exist.
@vercel

vercel Bot commented Oct 3, 2026 •

Copy link
Copy Markdown

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

Project Deployment Actions Updated
clean-stack Ready Ready Preview Oct 3, 2026 1:12am UTC
cleanstack Ready Ready Preview, v0 Oct 3, 2026 1:12am UTC

@DHYEY166
DHYEY166 merged commit 796cfb2 into main Oct 3, 2026
9 checks passed

This branch was successfully deployed

2 active deployments
Preview – cleanstack — 390dba89 Deployed Oct 3, 2026 by vercel[bot]
Preview – clean-stack — 390dba89 Deployed Oct 3, 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