Skip to content

[Fix] Retry the worker's job-claim callbacks while the public edge settles - #21

Merged
daniel-lxs merged 1 commit into
developfrom
fix/worker-dequeue-callback-retry
Jul 9, 2026
Merged

[Fix] Retry the worker's job-claim callbacks while the public edge settles#21
daniel-lxs merged 1 commit into
developfrom
fix/worker-dequeue-callback-retry

Conversation

@daniel-lxs

Copy link
Copy Markdown
Member

Problem

The first callbacks a docker worker makes — cloudJobs.dequeue (and cloudJobs.resume for resumed jobs) — go through the public URL (ngrok → Caddy edge). Right after the stack (re)starts, the edge can briefly answer 5xx or without a JSON content-type while its upstreams settle. The worker's fetch wrapper failed the whole job on the first bad response:

❌ Job <unknown> failed: Worker callback tRPC endpoint https://<public-url>/_roomote-api/trpc/cloudJobs.dequeue?batch=1 returned non-JSON content-type "missing".

The job is orphaned in dequeued (later recovered to idle by the controller) and the worker container lingers. Observed on a local dev stack: job created at 20:12:00, worker failed at 20:12:15, while the same URL served healthy JSON minutes later; an identical retried job succeeded end-to-end.

Fix

  • packages/sdk: the transport-retry allowlist (RETRYABLE_WORKER_TRPC_MUTATION_PATHS) becomes a map with optional per-path retry budgets. cloudJobs.dequeue and cloudJobs.resume are added with a longer budget (6 attempts, ~31s of exponential backoff) — claiming a job is idempotent server-side (FOR UPDATE SKIP LOCKED returns nothing on a second attempt), so replaying the claim is safe. Batched requests take the smallest budget across their paths, and explicit wrapper options still win so callers/tests can pin behavior.
  • apps/dev: after starting services, the dev CLI now polls the API health route through the public edge (<public-url>/_roomote-api/, up to 45s, warn-only) instead of only checking pm2 process state, so local stacks don't hand jobs to workers before the edge is serving.

Verification

  • 4 new unit tests in packages/sdk/src/client/index.test.ts (21 total pass): retries a no-content-type 502 on dequeue, the 6-attempt default budget, resume transport retry, and explicit-options precedence.
  • Live: restarted the dev stack (new "Checking public edge" step ran and passed), rebuilt the local worker release from this branch, and ran a mock-Slack job end-to-end — the worker claimed the job through the edge, answered, and reached waiting_for_prompt.

🤖 Generated with Claude Code

…ttles

The first callbacks a docker worker makes (cloudJobs.dequeue / resume) go
through the public URL, and a freshly (re)started ngrok/Caddy edge can briefly
answer 5xx or without a JSON content-type. The worker failed the whole job on
the first bad response, orphaning it in 'dequeued'.

Claiming a job is idempotent server-side (FOR UPDATE SKIP LOCKED), so add the
claim mutations to the retryable-path allowlist with a longer budget
(6 attempts, ~31s of backoff). Also have the dev CLI poll the API health route
through the public edge after starting services, so local stacks don't hand
jobs to workers before the edge is serving.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@roomote-roomote-v1

roomote-roomote-v1 Bot commented Jul 9, 2026

Copy link
Copy Markdown

No code issues found. See task

@daniel-lxs
daniel-lxs merged commit b9d67fb into develop Jul 9, 2026
1 check passed
@daniel-lxs
daniel-lxs deleted the fix/worker-dequeue-callback-retry branch July 9, 2026 05:17
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