Nobody has started this yet — be first.
Business impact
This bug breaks the TTL mechanism in both directions at once. A job that's still actively running can disappear from Redis before it finishes, because it's getting the short result TTL (meant only for finished results) instead of the long pending TTL -- a client polling a long-running job would suddenly get 404s partway through, indistinguishable from the job genuinely having vanished. And a completed job's result sticks around far longer than configured, because it's getting the long pending TTL instead of the short result TTL -- a promise this project's own README documents as a "privacy/cleanup guarantee" for whatever's in a job's result, quietly broken for every single completed job.
Problem
This is backwards: a terminal status (completed/failed/cancelled) gets pending_ttl_seconds (meant for jobs still in flight), and a non-terminal status gets result_ttl_seconds (meant only to apply once a job is actually finished).
Current behavior
app/store.py's update() computes ttl = pending_ttl_seconds if status in TERMINAL_STATUSES else result_ttl_seconds -- the two TTL values are paired with the wrong branches.
Expected behavior
A terminal job's document should get result_ttl_seconds. A non-terminal (still running) job's document should get pending_ttl_seconds.
Steps to reproduce
pytest practice_tickets/tests/test_ticket_09_ttl_selection_inverted.py -vSettings(result_ttl_seconds=1, pending_ttl_seconds=30), submit a job with duration_seconds: 4, wait 2 seconds, then GET /jobs/{id}?wait=0.404 job not found or result expired, for a job that is only 2 seconds into a 4-second run.Why this matters
The condition itself (status in TERMINAL_STATUSES) is correct -- it's exactly the right thing to branch on. The bug is purely in which value got assigned to which branch, the kind of mistake that's trivially easy to introduce (and just as easy to miss on a skim) because the line reads as sensible either way. This also fails tests/test_expiry.py::test_completed_job_expires_after_its_ttl in the project's own suite.
Suggested approach
Look at what result_ttl_seconds and pending_ttl_seconds are each documented to protect (see their docstrings in app/config.py), and check which one is currently paired with status in TERMINAL_STATUSES versus its else.
Acceptance criteria
Verification
pytest practice_tickets/tests/test_ticket_09_ttl_selection_inverted.py -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/ttl-selection-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/ttl-selection-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 inhttp://localhost:8000localhost:6379curl localhost:8000/healthz{"status": "ok", "redis": true}Work the tickets in practice_tickets/tickets/ (ordered easy → hard); each names one dedicated pytest file in practice_tickets/tests/:
python3 -m venv .venv && source .venv/bin/activate
pip install -r requirements-dev.txt
pytest practice_tickets/tests/test_ticket_01_completed_jobs_counted_as_failed.py -v # a single ticket
./practice_tickets/run_tickets.sh # all 15, clean pass/fail summary
Each ticket test runs in its own pytest process with a 60s timeout, so one hung/crashed ticket can't take down the whole run or hide another ticket's result. Run pytest tests/ (the project's own suite, against fakeredis, hermetic and fast) after each fix to check for regressions -- the README documents exactly which fixes are expected to change that suite's results.
Level 1
Fix a bug
Read existing behaviour, correct it.