Nobody has started this yet — be first.
Business impact
A reservation's TTL is fixed at creation time. A slow checkout flow (a customer stuck on a payment form, a flaky payment gateway) has no way to ask for more time before the reaper reclaims its hold -- the only option today is to fail the checkout and make the customer start over.
Problem
Service.ExtendReservation does not exist yet; there is no way to push out an active reservation's expires_at.
Current behavior
Calling Service.ExtendReservation currently panics with "TODO(ticket-21): Service.ExtendReservation not implemented".
Expected behavior
Service.ExtendReservation(ctx, id, extra time.Duration) (Reservation, error) pushes an active reservation's expires_at out by extra. It must behave exactly like Commit/Release in every other respect: reject a reservation that is not active (already committed, released, or expired) with ErrReservationNotActive, rather than silently reviving something that's already over.
Steps to reproduce
go test ./tickets/tests/... -run TestTicket21 -vWhy this matters
This needs the same concurrency-correctness the rest of the reservation lifecycle already has: the reservation row must be locked for the duration of the check-and-update (so a concurrent Commit/Release/reaper sweep can't race it), and an already-expired-but-not-yet-reaped reservation must be treated as expired, not extendable -- the same "opportunistic expiry" rule resolve already applies to Commit and Release.
Suggested approach
LockReservation (used by resolve, just above this method's stub) already does exactly the locking this needs. Look at how resolve structures its checks -- lock, check status, check whether now() is past expires_at -- and reuse that same shape for a simple instead of 's ledger-and-stock-effect logic (extending a hold doesn't touch or the ledger at all -- no quantity is moving between accounts).
Acceptance criteria
Verification
TEST_DATABASE_URL=postgresql://... go test ./tickets/tests/... -run TestTicket21 -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 feat/extend-reservationFix it and commit
Meet every acceptance criterion, and add a test that would have caught this.
Push the branch
$git push -u origin feat/extend-reservationSubmit 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 inUPDATE reservations SET expires_at = ...resolvesku_inventorySKIP LOCKEDhttp://localhost:8081localhost:5434flash-saleeveryday-widgetcurl localhost:8081/healthzgo run ./cmd/loadtest -url http://localhost:8081 -sku flash-sale -concurrency 10000Work the tickets in tickets/docs/ (ordered easy → hard); each names one dedicated Go test in tickets/tests/:
export TEST_DATABASE_URL=postgresql://inventory:inventory@localhost:5432/inventory_test?sslmode=disable
go test ./tickets/tests/... -run TestTicket24 -v # a single ticket
./tickets/run_tickets.sh # all 25, clean pass/fail summary
Tickets that don't touch Postgres (02, 07, 17, 19) run fine without TEST_DATABASE_URL; the rest t.Skip cleanly, not fail, if it's unset.
Level 2
Implement a feature
Extend the system within its own patterns.