Nobody has started this yet — be first.
Business impact
docker-compose.prod.yml runs this service under 4 separate gunicorn worker processes, each with its own independent Prometheus metric objects — nothing shares them across processes. A single scrape of GET /metrics currently only reflects whichever one worker process happened to answer that connection, not a true sum across all 4. This is called out explicitly in the project README's known limitations, and matters for the same reason GET /events/stats has the same per-process blind spot: a dashboard built on either number under-reports by roughly 4x, depending on which worker answers.
Problem
get_metrics_registry() is already the single place /metrics asks which registry to export, but its body always returns the plain global REGISTRY, ignoring the PROMETHEUS_MULTIPROC_DIR environment variable that prometheus_client's own multiprocess mode is built around.
Current behavior
With PROMETHEUS_MULTIPROC_DIR set to a real directory, get_metrics_registry() still returns the same plain global REGISTRY object it does when the variable is unset.
Expected behavior
When PROMETHEUS_MULTIPROC_DIR is set, get_metrics_registry() returns a registry backed by prometheus_client.multiprocess.MultiProcessCollector that sums the metric files every worker writes to that shared directory; when unset, behavior is unchanged (the plain global registry).
Steps to reproduce
pytest practice_tickets/tests/test_ticket_20_multiprocess_metrics.py -v — sets PROMETHEUS_MULTIPROC_DIR to a real directory and confirms get_metrics_registry() still returns the same global REGISTRY object.Why this matters
prometheus_client ships first-class support for exactly this multi-process scenario (a well-known limitation of any pre-fork server model), but it requires each worker to write its metric state to files in a shared directory and the reading side to use MultiProcessCollector against a fresh CollectorRegistry instead of the default global one. This ticket is scoped to the reading side — making get_metrics_registry() actually branch on PROMETHEUS_MULTIPROC_DIR — which is the piece this codebase currently gets wrong even before the writing side is considered.
Suggested approach
Look at get_metrics_registry() in app/metrics.py — note the already imported-but-unused os module at the top of the file (a hint, not an accident). You'll need prometheus_client.multiprocess.MultiProcessCollector and a fresh CollectorRegistry() to register it against, conditioned on whether os.environ.get("PROMETHEUS_MULTIPROC_DIR") is set.
Acceptance criteria
Verification
pytest practice_tickets/tests/test_ticket_20_multiprocess_metrics.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/multiprocess-metricsFix it and commit
Meet every acceptance criterion, and add a test that would have caught this.
Push the branch
$git push -u origin feat/multiprocess-metricsSubmit 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:5432curl localhost:8000/healthzcurl localhost:8000/readyzWork the tickets in practice_tickets/tickets/ (ordered easy → hard); each names one dedicated test in 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.
Level 2
Implement a feature
Extend the system within its own patterns.