This document is less about software architecture per-se, but rather about technical details deemed out-of-scope for the README.
-
based around the fantastic
rich
library for terminal output -
structural pattern matching, introduced in Python 3.10:
- initially used for fun, but not because any use cases were substantially easier using it,
- then dropped on 2022-07-16 since Python 3.10 is unsupported by AWS lambda,
- but since switched to Google Cloud Run, which is based on regular OCI containers (see Dockerfile), hence resolving the hell that is dependency management in serverless environments.
Fully serverless is still interesting since it's such a fitting use-case. The best solution seems to vendor all dependencies, instead of trying our luck with the serverless provider reading and correctly installing the dependencies for us (which often requires a
requirements.txt
instead of apoetry.lock
or similar).However, since this project treats self-hosting as a first-class citizen, going full serverless and abandoning providing Docker images entirely isn't an option anyway. Hosting serverlessly would be a split, required maintenance of two hosting options instead of just building one image and calling it a day.
-
fully typed using Python type hints, verified through
mypy --strict
(with additional, even stricter settings) -
structural logging with a JSON event stream output
-
pydantic
for fully typed data validation (e.g., for APIs), facilitated by automaticpydantic
model generation from e.g. OpenAPI specs like GitHub's or JSON Resume's, allowing full support frommypy
and the IDE when using said validated data -
12 Factor App conformance:
- Codebase: GitHub-hosted repo
- Dependencies: taken care of by uv
- Config: the app is configured using environment variables. Although problematic, this approach was chosen for its simplicity
- Backing Services: not applicable for this very simple app
- Build, release, run: handled through GitHub releases via git tags and release-please
- Processes: this simple app is stateless in and of itself
- Port binding: the
aiohttp
server part of the app acts as a standalone web server, exposing a port. That port can then be serviced by any arbitrary reverse proxy - Concurrency: covered by async functionality (in a single process and thread). This being a stateless app, horizontal scaling through additional processes is trivial (e.g. via serverless hosting), although vertical scaling will likely suffice indefinitely
- Disposability:
aiohttp
handlesSIGTERM
gracefully - Dev/prod parity: trivial to do for this simple app. If running on Windows, mind this issue. If running on Linux, no special precautions are necessary
- Logs: structured JSON logs are written directly to
stdout
- Admin processes: not applicable either
Very hard to find any, and even hard to google.
For example, bash curl curriculum vitae
will prompt Google to interpret curriculum vitae == resume
, which isn't wrong but curl resume
is an entirely unrelated query (concerned with resuming halted downloads and such).
Similar projects:
Related, but 'fake' hits: