Nobody has started this yet — be first.
Business impact
A job whose target never responds at all (hangs forever, or the network path is broken such that the worker's HTTP call never returns before the lease expires) is only ever recovered by the reaper's blind reclaim -- the worker itself never gets to call MarkRetry or MarkDead. If reclaiming doesn't increment attempt_count, that job retries forever: attempt_count stays frozen, it can never reach max_retries, and it never dead-letters. This is a silent resource leak with no ceiling -- a single misconfigured or unreachable target_url generates an unbounded stream of retries indefinitely, consuming worker capacity that should be going to healthy jobs, with nothing in the dead-letter queue to alert anyone that something is stuck.
Problem
pkg/queue/queue.go's ReclaimExpiredLeases requeues expired leases but never touches attempt_count in its UPDATE. Every reclaim leaves it exactly where it was.
Current behavior
After inserting a job_runs row with attempt_count = 3 and an already-expired leased_until, calling ReclaimExpiredLeases leaves attempt_count at 3 instead of 4.
Expected behavior
Every reclaim should increment attempt_count, exactly like an explicit MarkRetry call does -- a reclaim represents a failed attempt (the worker holding the lease never reported back), and it should count against the job's retry budget the same way an explicit failure does.
Steps to reproduce
Why this matters
This is a missing side effect in an UPDATE statement -- easy to omit because the statement still "does something correct" (it does requeue the row), just not everything it needs to.
Suggested approach
Compare this UPDATE's SET clause against MarkRetry's, right above it in the same file -- MarkRetry sets attempt_count explicitly to a caller-provided value; this one needs to increment the column's current value instead (since there's no separate caller-computed value here, the row itself needs to move it forward by one).
Acceptance criteria
Verification
TEST_DATABASE_URL="postgresql://chronos:chronos@localhost:5432/chronos?sslmode=disable" go test ./tickets/tests/... -run TestTicket13 -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/reclaim-attempt-countFix it and commit
Meet every acceptance criterion, and add a test that would have caught this.
Push the branch
$git push -u origin fix/reclaim-attempt-countSubmit 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 inhttp://localhost:8081app-1http://localhost:8082app-2http://localhost:8090curl localhost:8081/healthzcurl localhost:8081/readyzWork the tickets in tickets/docs/ (ordered easy → hard); each names one Go test in tickets/tests/. Most tickets need a real Postgres (tickets 4, 11, and 18 are pure-function tests and do not):
export TEST_DATABASE_URL="postgresql://chronos:chronos@localhost:5432/chronos?sslmode=disable"
go test ./tickets/tests/... -run TestTicket08 -v # a single ticket
./tickets/run_tickets.sh # all 20, clean pass/fail summary
Use -race when working on tickets 15, 16, or 17 (the concurrency ones) -- run_tickets.sh already does this for every ticket. Tickets 15 and 16 are adjacent bugs in the same function (pkg/leader/leader.go's lock-release path); fix ticket 16 first, since ticket 15's test keeps failing for ticket 16's reason until that one is fixed too.
Level 1
Fix a bug
Read existing behaviour, correct it.