A backpressure-safe FastAPI ingestion API built to swallow ~50,000 events/sec without ever doing one INSERT per event or growing an unbounded buffer.
Nobody has started this yet — be first.
Persisted-event count is always 0 (or garbage) after a flush
`GET /events/stats` and the Prometheus `/metrics` endpoint are the only way an on-call engineer can tell "is ingestion actually landing rows, or just accepting requests and quietly losing them downstream?" during an incident. Both ultimately depend on `AsyncpgInserter.insert_batch()` correctly reporting how many rows a batch actually persisted. If that number is wrong, every capacity dashboard is wrong, every "are we dropping data" alert is either permanently silent or permanently screaming, and the load test's own headline claim ("zero data loss, verified") in the project README is unverifiable — it would be reading a broken instrument.
About this project
A production-shaped async event ingestion service whose one hard rule is: never one per incoming event. Accepted events go onto a bounded in-process (never an unbounded list); a pool of flush workers drains it in batches, flushing whichever comes first, events collected or elapsed; each batch is written with one statement, making idempotency atomic and race-free without a -then-; and when the queue is full, new requests get a fast , not a growing buffer — that's the entire backpressure story. A real, measured load test () drives the service to tens of thousands of events/sec and cross-checks against Postgres row counts for a genuine zero-data-loss proof, and carries the constraint the whole dedupe design leans on.
The very first event from any device (sequence=0) is rejected
Any device/client that numbers its events starting at 0 (extremely common — it's the default for practically every counter, array index, and auto-increment convention in software) gets a 422 Unprocessable Entity on its very first event, before it has ever successfully sent anything. This isn't a degraded experience, it's a hard onboarding wall: support tickets show up as "the API rejects every single event we send," and a customer integrating for the first time has no way to know the fix is "start counting from 1" without reading this codebase's source.
INSERTasyncio.Queuebatch_max_sizebatch_max_wait_secondsINSERT ... SELECT * FROM unnest(...) ON CONFLICT (event_key) DO NOTHINGSELECTINSERT503load_test/async_load_test.pyGET /events/statssql/schema.sqlUNIQUE (event_key)Twenty tickets, ordered easy → hard: twelve are bugs deliberately injected into an otherwise-working codebase (an inverted any()/all() readiness check, a swapped pair of positional arguments that silently corrupts every row's device_id/event_type columns, a boolean guard using or where and was meant, a naive-vs-aware datetime mismatch that only breaks outside UTC); eight are enhancements with a stub already wired into the app (a panicking-equivalent no-op) so the codebase and its tests build before the real implementation is written. Every ticket has a dedicated pytest file that goes green when the fix is correct, and the practice_tickets README documents exactly which of the project's own pre-existing tests/ it collaterally turns from red to green along the way.
orandtests/practice_tickets/tickets/practice_tickets/tests/pytest practice_tickets/tests/test_ticket_01_persisted_count.py -v # a single ticket
./practice_tickets/run_tickets.sh # all 20, clean pass/fail summary
TICKET-17 needs a real Postgres to run at all (it checks which column a value lands in, which no fake/in-memory DB backend can meaningfully verify) — set TEST_DATABASE_URL=postgresql://<you>@localhost/ingest_test before running it or the full suite; without it, that one test is skipped, not failed.
How to run it locally, step by step.