refactor: drop make deploy and its refs/deploy stamps, the fleet deploys from infra/komodo; short readme and claude.md

This commit is contained in:
hh committed 2026-10-08 21:34:39 +02:00
1 parent a5345a9e4c
commit ee0f00ece8
5 files changed
+21 -68

No files matched your search

+3 -34
View File
@@ -4,23 +4,10 @@
{%- if 'taskiq_worker' in backend_services %}{% set _ = svc_modules.append("worker") %}{% endif -%}
{%- if 'kurigram_userbot' in backend_services %}{% set _ = svc_modules.append("userbot") %}{% endif -%}
{%- if 'scheduler' in backend_services and 'taskiq_worker' not in backend_services %}{% set _ = svc_modules.append("scheduler") %}{% endif -%}
{%- set app_services = [] -%}
{%- if 'api' in backend_services %}{% set _ = app_services.append("api") %}{% endif -%}
{%- if 'aiogram_bot' in backend_services %}{% set _ = app_services.append("bot") %}{% endif -%}
{%- if 'taskiq_worker' in backend_services %}{% set _ = app_services.append("worker") %}{% endif -%}
{%- if 'kurigram_userbot' in backend_services %}{% set _ = app_services.append("userbot") %}{% endif -%}
{%- if 'scheduler' in backend_services %}{% set _ = app_services.append("scheduler") %}{% endif -%}
{%- set has_script = dynamic_config and svc_modules -%}
{%- set has_scripts = dynamic_config or 'kurigram_userbot' in backend_services -%}
COMPOSE := {% if layout == 'part' %}cd .. && {% endif %}docker compose
{% if svc_modules %}IMAGE := {{ project_slug | replace('_', '-') }}/backend
IMAGE_INPUTS := pyproject.toml uv.lock Dockerfile
CODE := src{% if has_scripts %} scripts{% endif %}{% if serve_spa %} ../frontend{% endif %}
SERVICES := {{ app_services | join(' ') }}
changed = ! git diff --quiet $(1) -- $(2) 2>/dev/null
stamp = { git update-ref $(1) HEAD 2>/dev/null || true; }
{% endif %}
.PHONY: {% if layout == 'root' %}env recreate rebuild restart logs down deploy {% endif %}fmt check{% if svc_modules %} build pre-deploy post-deploy{% endif %}{% if database == 'postgres' %} migrate revision{% endif %}{% if has_script %} script{% endif %}{% if 'kurigram_userbot' in backend_services %} session{% endif %}
.PHONY: {% if layout == 'root' %}env recreate rebuild restart logs down {% endif %}fmt check{% if svc_modules %} build{% endif %}{% if database == 'postgres' %} migrate revision{% endif %}{% if has_script %} script{% endif %}{% if 'kurigram_userbot' in backend_services %} session{% endif %}
fmt:
uv run ruff format
@@ -34,20 +21,6 @@ check:
{% endif %}{% if svc_modules %}
build:
$(COMPOSE) build {{ svc_modules[0] }}
pre-deploy:
@if $(call changed,refs/deploy/backend,$(IMAGE_INPUTS)) || ! docker image inspect $(IMAGE) >/dev/null 2>&1; then \
$(MAKE) build && $(call stamp,refs/deploy/backend) && $(call stamp,refs/deploy/backend-code); \
fi
{% if database == 'postgres' %} @if ($(COMPOSE) config --services) | grep -qx postgres; then ($(COMPOSE) up -d --wait postgres); fi
$(MAKE) migrate
{% endif %}
post-deploy:
@if $(call changed,refs/deploy/backend-code,$(CODE)); then \
running=$$($(COMPOSE) ps --services --status running | grep -x $(addprefix -e ,$(SERVICES))); \
if [ -n "$$running" ]; then ($(COMPOSE) restart $$running); fi; \
$(call stamp,refs/deploy/backend-code); \
fi
{% endif %}{% if layout == 'root' %}
env:
@fresh=; test -f .env || { cp .env.example .env; fresh=1; }; \
@@ -74,11 +47,7 @@ logs:
down:
$(COMPOSE) down
{% if svc_modules %}
deploy: pre-deploy
$(COMPOSE) up -d
$(MAKE) post-deploy
{% endif %}{% endif %}{% if database == 'postgres' %}
{% endif %}{% if database == 'postgres' %}
migrate:
$(COMPOSE) run --rm migrator $(or $(filter-out $@,$(MAKECMDGOALS)),upgrade head)
@@ -1,16 +0,0 @@
## Checking commands
After writing code, always run from `backend/`:
```shell
ruff format
ruff check --fix
ty check
```
## Imports
Every service imports only what it needs to start. `make check` runs `scripts/check_imports.py`, which fails when a service loads a heavy package it is not allowed; `SERVICES` there is the contract, extend it on purpose.
- Package `__init__` files don't re-export clients or SDKs.
- An SDK used by one function is imported inside it. On an async path load it first with `await preload("<module>")` from `utils.imports`, so the event loop never waits on the import.
- Types used in Dishka provider signatures and `FromDishka[...]` stay real top-level imports.
## Dynamic config
`config()` returns a copy of an in-process snapshot: no database round-trip per call, changes from any process show up within 5 s through a version number on the config record. Never `save()` a config you read; write through `DynamicConfig.update_config(section=...)` (Mongo) or `ConfigRepository.update(section=...)`/`save(...)` (Postgres), which bump the version atomically. Counters and other hot data don't belong in the config, give them their own collection or table with atomic increments.
@@ -0,0 +1,10 @@
## Checking commands
After writing code, always run from `backend/`:
```shell
make fmt
make check
```
{% if backend_services or dynamic_config %}
{% endif %}{% if backend_services %}Mind startup imports: `make check` runs `scripts/check_imports.py`.
{% endif %}{% if dynamic_config %}Change dynamic config only through its update methods.
{% endif %}
@@ -1,22 +1,16 @@
{%- set targets = [] -%}
{%- if database == 'postgres' %}{% set _ = targets.append("`make migrate` (`make migrate downgrade -1` to roll back), `make revision m=\"message\"`") %}{% endif -%}
{%- if database == 'postgres' %}{% set _ = targets.append("`make migrate`, `make revision m=\"message\"`") %}{% endif -%}
{%- if dynamic_config and backend_services %}{% set _ = targets.append("`make script name`") %}{% endif -%}
{%- if 'kurigram_userbot' in backend_services %}{% set _ = targets.append("`make session`") %}{% endif -%}
# {{ project_name }}
{% if project_description and project_description != project_name %}
{{ project_description }}
{% endif %}
Runs in Docker, locally the same way as in production. `COMPOSE_PROFILES` in `.env` selects the services that run on this machine. `docker-compose.override.yml` holds what differs between machines: published ports and the aliases on the external `caddy` network.
```sh
make env
make recreate
make env # .env and docker-compose.override.yml from the examples
make recreate # the services in COMPOSE_PROFILES
make check
```
`make env` creates `.env` and `docker-compose.override.yml` from their examples. `make recreate` starts the selected profiles, `make rebuild` builds the image first, `make logs`, `make restart` and `make down` do what they say.
{% if backend_services %}To deploy, `git pull && make deploy`. It runs `make pre-deploy`, which builds the image only when `pyproject.toml`, `uv.lock` or `Dockerfile` changed{% if database == 'postgres' %} and applies migrations{% endif %}, then `docker compose up -d`, then `make post-deploy`, which restarts the services whose mounted code changed. A deploy system with its own `up` step calls the two hooks around it. What was built and started is remembered as `refs/deploy/*` in the clone.
In the fleet, production is deployed from `infra/komodo` instead (git mode of Komodo, see `docs/architecture.md` there): Komodo clones this repo, and a layer plus `deploy.sh` in the stack's directory tag images by the hash of what they bake in, write `.env` from sops and run migrations before the code. The repo only has to stay a plain recipe: images built from `build:` in compose, migrations as the `migrator` service when there is a database, `caddy/site.caddy`. `make deploy` and `refs/deploy/*` are for a checkout deployed by hand.
{% endif %}`make fmt` formats, `make check` runs ruff and ty.{% if targets %} Also {{ targets | join(", ") }}.{% endif %}
{% if targets %}
Also {{ targets | join(", ") }}.
{% endif %}