436613bfde
Bug: la dashboard NiceGUI mostrava "Your browser does not support ES modules" perche' le asset URL nell'HTML erano doppio-prefissate: /strategy_crypto_gui/strategy_crypto_gui/_nicegui/... Root cause: il middleware traefik.stripprefix aggiunge automaticamente X-Forwarded-Prefix header. uvicorn/Starlette legge il header e setta root_path automaticamente, raddoppiando con quello passato esplicitamente a ui.run(root_path="/strategy_crypto_gui"). Fix: traefik.replacepathregex strippa il prefix senza propagare il header. uvicorn vede solo il root_path da ui.run -> asset prefissati una sola volta. - replacepathregex.regex=^/strategy_crypto_gui(/.*|$) - replacepathregex.replacement=$1 Verifica end-to-end: - page: HTTP 200, asset prefix singolo - /strategy_crypto_gui/_nicegui/3.12.0/static/socket.io.min.js: 200 - / (root): 404 (atteso) NB: dopo cambio label, necessario `docker restart traefik-traefik-1` per forzare refresh discovery (problema noto Traefik con label durante recreate container nello stesso ciclo). Annotare per future modifiche middleware. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
124 lines
4.9 KiB
YAML
124 lines
4.9 KiB
YAML
# docker-compose.yml — Multi-Swarm Coevolutive
|
|
#
|
|
# Due servizi della strategia crypto, condividono la stessa immagine
|
|
# `multi-swarm-coevolutive:dev` buildata dal Dockerfile root (uv workspace):
|
|
#
|
|
# * strategy-crypto-paper — paper-trading runner long-running
|
|
# (scripts/run_paper_trading.py)
|
|
# * strategy-crypto-gui — NiceGUI dashboard esposta da Traefik su
|
|
# https://swarm.${DOMAIN_NAME:-tielogic.xyz}/strategy_crypto_gui
|
|
#
|
|
# Entrambi joinano la rete external `traefik` cosi' il client Cerbero
|
|
# risolve direttamente l'host `cerbero-mcp` (porta 9000) senza passare
|
|
# dal gateway pubblico ne' dal TLS.
|
|
#
|
|
# Pattern N strategie future: aggiungere strategy-<asset>-paper + strategy-<asset>-gui
|
|
# con PathPrefix(/strategy_<asset>_gui) e DASHBOARD_ROOT_PATH dedicato.
|
|
#
|
|
# Dati persistenti via bind mount dalla cartella del repo:
|
|
# ./data cache OHLCV intermedia
|
|
# ./series cache parquet per timeframe/symbol
|
|
# ./state contiene runs.db (GA) + strategy_crypto.db (paper) + WAL/SHM
|
|
# ./src/strategy_crypto/strategy_crypto/strategies JSON freezate (ro)
|
|
#
|
|
# Secrets (token Cerbero + OpenRouter): caricati da .env via env_file.
|
|
|
|
networks:
|
|
traefik:
|
|
external: true
|
|
|
|
x-swarm-env: &swarm-env
|
|
# Override: rotta interna verso cerbero-mcp (no TLS, no traefik hop)
|
|
CERBERO_BASE_URL: http://cerbero-mcp:9000
|
|
# Override: path container per persistenza
|
|
DATA_DIR: /app/data
|
|
SERIES_DIR: /app/series
|
|
# DB separati per dominio:
|
|
GA_DB_PATH: /app/state/runs.db
|
|
STRATEGY_CRYPTO_DB_PATH: /app/state/strategy_crypto.db
|
|
# Subpath sotto cui la dashboard NiceGUI e' esposta da Traefik.
|
|
# IMPORTANT: NON usare StripPrefix middleware con questo. NiceGUI/Starlette
|
|
# gestisce internamente il root_path su request path che ARRIVANO con prefix.
|
|
# StripPrefix causa doppio prefix negli asset URL (NiceGUI prefixa + uvicorn
|
|
# rilegge X-Forwarded-Prefix e prefixa di nuovo).
|
|
DASHBOARD_ROOT_PATH: /strategy_crypto_gui
|
|
|
|
services:
|
|
strategy-crypto-paper:
|
|
build:
|
|
context: .
|
|
dockerfile: Dockerfile
|
|
image: multi-swarm-coevolutive:dev
|
|
container_name: strategy-crypto-paper
|
|
restart: unless-stopped
|
|
networks: [traefik]
|
|
env_file: .env
|
|
environment:
|
|
<<: *swarm-env
|
|
volumes:
|
|
- ./data:/app/data
|
|
- ./series:/app/series
|
|
- ./state:/app/state
|
|
- ./src/strategy_crypto/strategy_crypto/strategies:/app/strategies:ro
|
|
# Niente HTTP da controllare: ci affidiamo a `restart: unless-stopped`
|
|
# e ai log per la liveness del runner.
|
|
command:
|
|
- python
|
|
- /app/scripts/run_paper_trading.py
|
|
- --name=${PAPER_RUN_NAME:-phase3-papertrade-prod}
|
|
- --initial-capital=${PAPER_INITIAL_CAPITAL:-1000}
|
|
- --fees-bp=${PAPER_FEES_BP:-5.0}
|
|
- --poll-seconds=${PAPER_POLL_SECONDS:-300}
|
|
- --lookback-bars=${PAPER_LOOKBACK_BARS:-500}
|
|
- --strategies-dir=/app/strategies
|
|
labels:
|
|
- com.centurylinklabs.watchtower.enable=true
|
|
|
|
strategy-crypto-gui:
|
|
image: multi-swarm-coevolutive:dev
|
|
build:
|
|
context: .
|
|
dockerfile: Dockerfile
|
|
container_name: strategy-crypto-gui
|
|
restart: unless-stopped
|
|
networks: [traefik]
|
|
env_file: .env
|
|
environment:
|
|
<<: *swarm-env
|
|
volumes:
|
|
# Dashboard legge entrambi i DB: state/ in read-only (WAL: vedi nota)
|
|
- ./state:/app/state:ro
|
|
- ./data:/app/data:ro
|
|
- ./series:/app/series:ro
|
|
entrypoint:
|
|
- python
|
|
- -m
|
|
- strategy_crypto.frontend.nicegui_app
|
|
command: []
|
|
healthcheck:
|
|
test:
|
|
- "CMD"
|
|
- "python"
|
|
- "-c"
|
|
- "import os, urllib.request; urllib.request.urlopen(f'http://localhost:{os.environ.get(\"SWARM_DASHBOARD_PORT\",\"8080\")}/', timeout=3).close()"
|
|
interval: 30s
|
|
timeout: 5s
|
|
retries: 3
|
|
start_period: 30s
|
|
labels:
|
|
- traefik.enable=true
|
|
- traefik.docker.network=traefik
|
|
- "traefik.http.routers.strategy-crypto-gui.rule=Host(`swarm.${DOMAIN_NAME:-tielogic.xyz}`) && PathPrefix(`/strategy_crypto_gui`)"
|
|
- traefik.http.routers.strategy-crypto-gui.tls=true
|
|
- traefik.http.routers.strategy-crypto-gui.entrypoints=websecure
|
|
- traefik.http.routers.strategy-crypto-gui.tls.certresolver=mytlschallenge
|
|
- "traefik.http.services.strategy-crypto-gui.loadbalancer.server.port=${SWARM_DASHBOARD_PORT:-8080}"
|
|
# replacepathregex (NON stripprefix): strippa il prefix dalla request senza
|
|
# aggiungere X-Forwarded-Prefix header. uvicorn vede solo root_path da
|
|
# ui.run(root_path=...), quindi gli asset URL vengono prefissati una sola
|
|
# volta (no doppio prefix come succederebbe con stripprefix).
|
|
- "traefik.http.middlewares.strategy-crypto-replace.replacepathregex.regex=^/strategy_crypto_gui(/.*|$$)"
|
|
- "traefik.http.middlewares.strategy-crypto-replace.replacepathregex.replacement=$$1"
|
|
- "traefik.http.routers.strategy-crypto-gui.middlewares=strategy-crypto-replace"
|
|
- com.centurylinklabs.watchtower.enable=true
|