Thermograph monorepo: graded-climate API + SSR frontend + infra, domain-specific containerized deploys
Prod runs 3 uvicorn workers, but the in-process subscription notifier was started in every worker's lifespan (it was written assuming a single-worker deploy). Its sweep fetches recent-forecast/archive data from Open-Meteo on a 15-min timer independent of any request, so running it 3× tripled the background upstream load against a shared quota — the source of the overnight 429/503 rate-limit errors in logs/errors, and 3× redundant subscription scans. Elect one worker to own the notifier via a non-blocking exclusive flock on a lockfile (THERMOGRAPH_SINGLETON_LOCK): the first worker wins and holds the fd for its lifetime; others stand down; the OS releases the lock if the leader dies, so a restart re-elects cleanly. Unset (single worker / dev / tests) always wins, so behavior there is unchanged. Mirrors the shared-metrics store's env-selected cross-worker coordination. The neighbor warmer stays per-worker on purpose: each worker drains its own request-fed queue, so gating it would leave non-leader queues undrained. - backend/singleton.py: flock-based leader election (claim()). - backend/app.py: gate notify.start() on singleton.claim(). - deploy/thermograph.service: default THERMOGRAPH_SINGLETON_LOCK to data/notifier.lock (needs the unit reinstalled on prod to take effect). - deploy/thermograph.env.example: document it alongside WORKERS. - Tests: leader election — single-worker default, first-wins, idempotent re-claim, second-holder stands down, re-election after release. 183 passed. Co-authored-by: root <root@vmi3417050.contaboserver.net> |
||
|---|---|---|
| templates | ||
| tests | ||
| api_accounts.py | ||
| app.py | ||
| audit.py | ||
| cities.json | ||
| cities.py | ||
| cities_flavor.json | ||
| city_events.py | ||
| climate.py | ||
| content.py | ||
| db.py | ||
| gen_cities.py | ||
| gen_flavor.py | ||
| grading.py | ||
| grid.py | ||
| indexnow.py | ||
| metrics.py | ||
| migrate.py | ||
| models.py | ||
| notify.py | ||
| places.py | ||
| push.py | ||
| requirements-dev.txt | ||
| requirements.txt | ||
| schemas.py | ||
| singleton.py | ||
| store.py | ||
| users.py | ||
| views.py | ||
| warm_cities.py | ||