Nobody has started this yet — be first.
Business impact
This function is the crash-recovery safety net documented in the project's own README: "an instance dies while a row is claimed -> ResumeStuckProcessing, called by every replica at startup, requeues any row left processing past a grace window." With the comparison inverted, that safety net does the opposite of its job on both sides at once: it steals rows a healthy, currently-working replica legitimately has in flight (risking a real duplicate bank call under just the wrong timing), and it leaves genuinely crashed rows stuck processing forever -- exactly the "a payment silently gets lost in limbo after a crash" scenario the whole outbox design exists to prevent.
Problem
ResumeStuckProcessing(ctx, olderThan) requeues rows whose updated_at is more recent than olderThan ago (i.e., recently claimed, likely still legitimately in flight) and leaves alone rows older than that (i.e., genuinely stuck).
Current behavior
A row claimed only moments ago (still legitimately in flight on a live replica) gets requeued to pending by ResumeStuckProcessing, while a genuinely long-abandoned row is left untouched.
Expected behavior
It should requeue rows older than olderThan (abandoned) and leave alone recently-claimed ones (still legitimately in flight).
Steps to reproduce
TEST_DATABASE_URL=postgresql://... go test ./tickets/tests/... -run TestTicket17 -v
This also collaterally breaks the project's own TestDispatcher_ResumeStuckProcessing_RequeuesCrashedRow (in internal/outbox/dispatcher_test.go).
Why this matters
Look at the SQL in ResumeStuckProcessing: WHERE status = 'processing' AND updated_at <comparison> now() - $1::interval. The comparison operator determines which side of "how long ago" counts as stale.
Suggested approach
Think through what "older than olderThan" means in terms of a timestamp comparison against now() - olderThan: is a row whose updated_at is before that cutoff the old one, or the recent one?
Acceptance criteria
Verification
TEST_DATABASE_URL=postgresql://... go test ./tickets/tests/... -run TestTicket17 -v && TEST_DATABASE_URL=postgresql://... go test ./internal/outbox/... -run TestDispatcher_ResumeStuckProcessing -v
Hints (0/2)
Try it without hints first — the reading is the exercise.
Working on this ticket
Work on a branch named for the ticket — that's what you'll submit.
Branch off your fork
Sign in to create it automatically, or do it yourself:
$git checkout -b fix/resume-stuck-processing-invertedFix it and commit
Meet every acceptance criterion, and add a test that would have caught this.
Push the branch
$git push -u origin fix/resume-stuck-processing-invertedSubmit it below
Paste your fork URL and the branch name, with a short write-up of the root cause.
Questions
Ask about anything unclear in the ticket — the maintainer and anyone who has solved it can answer. Please don't post full solutions.
Sign in to ask a question or reply.
Sign indocker composepaystate/paystate/go.modreplace reliable => ../reliabledocker compose up --buildpaystate/context: ..docker-compose.ymlCREATED_TIMEOUTAUTHORIZED_TIMEOUTWork the tickets in tickets/docs/ (ticket-01 through ticket-25); each names one Go test in tickets/tests/:
TEST_DATABASE_URL=postgresql://... go test ./tickets/tests/... -run TestTicket01 -v # a single ticket
TEST_DATABASE_URL=postgresql://... ./tickets/run_tickets.sh # all 25, clean pass/fail summary
Tickets that don't touch Postgres (02, 03, 04, 05, 06, 14, 15, 24) run fine without TEST_DATABASE_URL set; the rest report FAIL with a "TEST_DATABASE_URL not set" message if it's missing. make test-race runs the full go test -race -p 1 ./... suite the same way.
Level 1
Fix a bug
Read existing behaviour, correct it.