services: # ── Always-on infrastructure ────────────────────────────── router: image: nginx:alpine restart: unless-stopped ports: - "5000:80" volumes: - ./router/default.conf:/etc/nginx/conf.d/default.conf:ro networks: - net healthcheck: test: ["CMD", "nginx", "-t"] interval: 30s timeout: 5s litestream: image: litestream/litestream:latest restart: unless-stopped # Auto-restore from R2 if DB file is missing, then start continuous replication. # Handles: new server, deleted volume, disaster recovery. entrypoint: /bin/sh command: - -c - | if [ ! -f /app/data/app.db ]; then echo "==> No database found, restoring from R2..." litestream restore -config /etc/litestream.yml /app/data/app.db \ || echo "==> No backup found, starting fresh" fi exec litestream replicate -config /etc/litestream.yml env_file: ./padelnomics/.env volumes: - app-data:/app/data - ./padelnomics/litestream.yml:/etc/litestream.yml:ro healthcheck: disable: true # ── Blue slot ───────────────────────────────────────────── blue-app: profiles: ["blue"] build: context: ./padelnomics restart: unless-stopped env_file: ./padelnomics/.env environment: - DATABASE_PATH=/app/data/app.db volumes: - app-data:/app/data networks: - net healthcheck: test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:5000/health')"] interval: 10s timeout: 5s retries: 3 start_period: 15s blue-worker: profiles: ["blue"] build: context: ./padelnomics restart: unless-stopped command: python -m padelnomics.worker env_file: ./padelnomics/.env environment: - DATABASE_PATH=/app/data/app.db volumes: - app-data:/app/data networks: - net blue-scheduler: profiles: ["blue"] build: context: ./padelnomics restart: unless-stopped command: python -m padelnomics.worker scheduler env_file: ./padelnomics/.env environment: - DATABASE_PATH=/app/data/app.db volumes: - app-data:/app/data networks: - net # ── Green slot ──────────────────────────────────────────── green-app: profiles: ["green"] build: context: ./padelnomics restart: unless-stopped env_file: ./padelnomics/.env environment: - DATABASE_PATH=/app/data/app.db volumes: - app-data:/app/data networks: - net healthcheck: test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:5000/health')"] interval: 10s timeout: 5s retries: 3 start_period: 15s green-worker: profiles: ["green"] build: context: ./padelnomics restart: unless-stopped command: python -m padelnomics.worker env_file: ./padelnomics/.env environment: - DATABASE_PATH=/app/data/app.db volumes: - app-data:/app/data networks: - net green-scheduler: profiles: ["green"] build: context: ./padelnomics restart: unless-stopped command: python -m padelnomics.worker scheduler env_file: ./padelnomics/.env environment: - DATABASE_PATH=/app/data/app.db volumes: - app-data:/app/data networks: - net volumes: app-data: networks: net: