docker-compose.override.yml
Rama main · réplica de lectura del repositorio original.
# Local development, on a laptop. `make dev`, or a bare `docker compose up` in
# a checkout - Compose merges this file over `docker-compose.yml` on its own
# whenever both are in the directory, which is what makes the same base file
# pull published images in an empty directory and build from source in a clone.
#
# What it changes, and nothing else:
#
# - the backend image is built from this tree rather than pulled, and tagged
# `agenticos_backend:dev` so `migrate` and `worker` run the same build;
# - the source is bind-mounted and the API runs under the reload supervisor, so
# an edit is live without a rebuild;
# - the console is built from `frontend/` and put behind the `console`
# profile, so `make dev` does not fight `bun dev` on the host for :3000 -
# `make dev-frontend` starts it;
# - Postgres and Redis publish their ports, so psql, a GUI client and the test
# suite can reach them from the host.
#
# There used to be a `docker-compose.dev.yml` whose header claimed it was
# identical to the local file. It was not: it had drifted and lost
# `--ws websockets-sansio`, and it was the file `make dev` used - so the chat
# websocket 500'd on handshake for anyone developing locally. This file cannot
# drift that way, because it does not repeat anything: what it does not name, it
# inherits.
services:
browser:
# Built from this tree, like the backend, so a change to the browser image is
# tried before it is published.
build:
context: ./docker/browser
image: agenticos_browser:dev
migrate:
image: agenticos_backend:dev
pull_policy: never
app:
# The repository root, not `backend/`, so `emails/compiled/` is in the image
# - backend/Dockerfile says why. `make dev-rebuild` forces this build.
build:
context: .
dockerfile: backend/Dockerfile
args:
# Optional engines to build into the dev image, as `uv sync` flags.
# Empty unless `.env` sets it, so a plain `make dev` is unchanged.
# `BACKEND_EXTRAS="--extra browser"` is how browser automation, and the
# picture `preview_artifact` draws with the `artifact-render` profile,
# become runnable locally; `backend/Dockerfile` says why it is a build
# argument.
EXTRAS: ${BACKEND_EXTRAS:-}
image: agenticos_backend:dev
volumes:
- ./backend/app:/app/app:ro
- ./backend/cli:/app/cli:ro
- ./emails:/app/emails:ro
environment:
- DEBUG=true
- ENVIRONMENT=local
# Not `uvicorn --reload` directly. Its reloader is a file watcher, not a
# process supervisor: when the kernel kills the worker - an OOM kill is the
# realistic way - it neither reaps it nor replaces it, so PID 1 stays alive,
# this container stays `Up`, `restart:` has nothing to act on, and nothing is
# listening. `cli/reload_supervisor.py` is the same reloader with a worker the
# kernel killed replaced within about five seconds.
#
# It also replaces a worker that is alive but whose event loop has stopped
# turning - deadlocked, spinning, or stopped - which has no exit code and so
# looks healthy to everything else here. The worker beats from its own event
# loop and the supervisor replaces it after fifteen silent seconds. Set
# `EVENT_LOOP_WEDGED_AFTER` in `backend/.env` to change that, or to `0` to
# switch it off, which is what a breakpoint needs: a stopped event loop is
# exactly what the check is looking for.
#
# The same variable switches off `app/core/watchdog.py`, which judges the
# same loop from inside the worker and is what covers the stacks with no
# supervisor. Here it is the faster of the two judges; the supervisor is
# still the only one that can see a worker stopped outright, which cannot
# run a watchdog of its own.
#
# It, and not `cli.commands server run --reload`, because that entrypoint
# imports `app.main` and would put the whole application - 464 MB against
# 28 MB - inside a reloader that never serves a request.
command: python -m cli.reload_supervisor --host 0.0.0.0 --port 8000
worker:
image: agenticos_backend:dev
pull_policy: never
volumes:
- ./backend/app:/app/app:ro
environment:
- DEBUG=true
# One ingest child rather than two: each holds an imported application,
# and on the machine you are also writing code on that is memory better
# left to the editor. The worker does not reload; `docker compose restart
# worker` picks up an edit.
- WORKER_INGEST_CHILDREN=${WORKER_INGEST_CHILDREN:-1}
frontend:
build:
context: ./frontend
dockerfile: Dockerfile
image: agenticos_frontend:dev
profiles: [console]
db:
ports:
- "5432:5432"
redis:
ports:
- "6379:6379"