Nobody has started this yet — be first.
Business impact
The main live loop in event_stream() checks whether the client has disconnected on every iteration, so a client that goes away while idle is noticed promptly. The backlog replay loop -- which can iterate over up to the configured backlog length (1000 by default) of entries for a user reconnecting after a long time away -- has no such check at all. If a client disconnects partway through a large replay, event_stream() keeps formatting and yielding every remaining backlog entry to a connection that's already gone, for however long that takes, before it ever gets a chance to notice -- wasted server work under exactly the load pattern (a long-absent user with a full backlog) that matters most.
Problem
The backlog replay for loop in event_stream() has no disconnect check at all, unlike the live while True loop a few lines below it.
Current behavior
Seeding a 6-entry backlog, reading 1 entry, then flipping the client's disconnected state to True, the generator keeps yielding backlog entries past that point instead of stopping within a read or two.
Expected behavior
The backlog replay loop should check for disconnection the same way the live loop does, so a client that disconnects mid-replay is noticed within about one iteration, not after the entire remaining backlog has been processed.
Steps to reproduce
See practice_tickets/tests/test_ticket_11_disconnect_during_replay.py: seed a 6-entry backlog, read 1 entry, then flip the fake request's disconnected state to True -- the generator keeps yielding all 5 remaining entries instead of stopping within 1-2 more reads.
Why this matters
This matters most exactly when it's most expensive: a user reconnecting after being offline for a while -- the scenario this whole project is built to handle well -- is the same user whose backlog replay has the most entries to get through. A disconnect check that only exists in the live loop protects the cheap, common case and misses the expensive, less common one.
Suggested approach
Look at the disconnect check at the top of the while True loop in event_stream() -- the backlog for loop just above it is missing the equivalent check. The check needs to go before doing the work to format and yield the next entry, not after, so it actually saves the wasted work.
Acceptance criteria
Verification
pytest practice_tickets/tests/test_ticket_11_disconnect_during_replay.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 feat/disconnect-not-checked-during-replayFix it and commit
Meet every acceptance criterion, and add a test that would have caught this.
Push the branch
$git push -u origin feat/disconnect-not-checked-during-replaySubmit 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:8000http://localhost:8001Authorization: Bearer <user_id>X-User-Id: <user_id>curl localhost:8000/healthz
curl -N -H "Authorization: Bearer alice" localhost:8000/notifications/stream
# watch `: heartbeat` lines arrive roughly every 15s with no other traffic
Work the tickets in practice_tickets/tickets/ (ordered easy → hard); each names one dedicated pytest test in practice_tickets/tests/:
pytest practice_tickets/tests/test_ticket_01_heartbeat_default_margin.py -v # a single ticket
./practice_tickets/run_tickets.sh # all 15, clean pass/fail summary
Tickets 14 and 15 need genuinely concurrent, long-lived streams, which the ASGI test transport used everywhere else in this project can't represent -- their tests spin up a real (short-lived) uvicorn server on a loopback socket instead (LiveServer in practice_tickets/tests/conftest.py).
Level 2
Implement a feature
Extend the system within its own patterns.