diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index c8e1b84..fc4501c 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -52,11 +52,22 @@ when and why this was added. ## ADR: hosting platform Considered Vercel (rejected: serverless-only Python, no persistent -in-memory state, incompatible with this service's cache design). Chose -Render as primary (zero card on file, real cost is a slower cold start -after idle) over Cloud Run (technically better fit for the persistent- -container model, but requires a card on file even though usage should -stay within the free tier). See `README.md` deployment section for the -current live choice; check there before assuming this ADR reflects where -it's actually running today, ADRs record reasoning at decision time, they -don't self-update. +in-memory state, incompatible with this service's cache design). +Originally chose Render as primary (zero card on file, real cost was a +slower cold start after idle) over Cloud Run (technically better fit +for the persistent-container model, but requires a card on file even +though usage should stay within the free tier). + +Revisited for the first production deployment and switched to Cloud +Run: the card-on-file requirement was accepted deliberately, with a $1 +budget alert as the concrete mitigation (a service expected to cost $0 +means any alert firing at all is the signal, not a soft limit), in +exchange for the persistent-container model actually matching this +service's in-memory cache design instead of working around Render's +sleep-and-wake cycle. `--min-instances 0` keeps it free at idle the +same way Render's sleep did, just without the cold-start latency on +wake. + +See `README.md`'s deployment section for the current live choice; check +there before assuming this ADR reflects where it's actually running +today, ADRs record reasoning at decision time, they don't self-update. diff --git a/CHANGELOG.md b/CHANGELOG.md index fc2088f..e7ad9c7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,31 @@ All notable changes to this project are documented here. Format loosely follows [Keep a Changelog](https://keepachangelog.com/). +## [Unreleased] + +### Changed + +- Hosting switched from the planned Render deployment to Google Cloud + Run for the first production deployment (`--min-instances 0`, + `--max-instances 3`, `us-central1`), accepting the card-on-file + tradeoff in exchange for a persistent-container model that matches + this service's in-memory cache design. A $1 budget alert is the + concrete mitigation. See `ARCHITECTURE.md`'s ADR section for the full + reasoning. + +### Fixed + +- `Dockerfile` only copied `main.py`, never `constants.py`, so the + built image crashed on startup with `ModuleNotFoundError` before + `uvicorn` ever bound to the port. Caught by the first real deploy + attempt; `python3 -m py_compile main.py` never catches this since it + runs against the full checked-out repo, not the trimmed set of files + the Dockerfile actually copies into the image. +- The fix for the above (`COPY main.py constants.py .`) built fine + locally under BuildKit but failed on Cloud Build's classic builder, + which enforces the Dockerfile spec strictly: a multi-source `COPY`'s + destination must end with `/`. + ## [1.0.0] - initial release ### Added diff --git a/README.md b/README.md index ea8ac70..b2b289e 100644 --- a/README.md +++ b/README.md @@ -45,9 +45,9 @@ minutes thereafter. This repo holds no copy of the record data itself; ## Deployment -Deployed on Render. See `ARCHITECTURE.md`'s ADR section for why Render was -chosen over Cloud Run and Vercel, and what would have to change to revisit -that. +Deployed on Google Cloud Run (`--min-instances 0`, scales to zero at +idle). See `ARCHITECTURE.md`'s ADR section for the full reasoning, +including why Render was the original choice and what changed. ## Contributing