Files
enduro-trails/docker-compose.yml
claude-bot 543099b740
All checks were successful
CI / lint (push) Successful in 4s
CI / test (push) Successful in 12s
CI / build (push) Successful in 2s
CI / lint (pull_request) Successful in 4s
CI / test (pull_request) Successful in 12s
CI / build (pull_request) Successful in 2s
fix(infra): use python urllib for container healthcheck (ET-015)
Базовый образ `python:3.12-slim` не содержит `curl`, поэтому текущий
healthcheck `["CMD", "curl", "-f", ...]` всегда падает (`exec: "curl":
executable file not found`), и контейнер `enduro-trails-app-1` висит
в статусе `unhealthy` (≥31 час, FailingStreak 3762 при RestartCount 0),
несмотря на то что приложение исправно отвечает HTTP 200 на /api/health.

Заменяем healthcheck на python one-liner через stdlib `urllib.request`
(ADR-020). Изменения:

  • docker-compose.yml, сервис app:
      test: ["CMD", "python", "-c",
             "import urllib.request,sys; sys.exit(0 if
              urllib.request.urlopen(...timeout=3).status == 200 else 1)"]
      + start_period: 20s
    interval/timeout/retries сохранены (30s / 5s / 3).
    Внутренний urlopen(timeout=3) строго меньше внешнего healthcheck
    timeout=5s (AC-07).

  • Dockerfile НЕ меняется (никаких apt-get install curl/wget — BRD §6,
    AC-04). Деплой без ребилда: `docker compose up -d app` достаточно.

  • src/api/main.py НЕ меняется. Контракт /api/health сохранён (AC-08).

Покрытие:
  - tests/static/test_healthcheck_compose.py — 10 тестов (ST-01..ST-07
    + защита от регресса по target URL / start_period / baseline params).
  - tests/unit/test_healthcheck_oneliner.py — 6 тестов (UT-01..UT-03),
    исполняют ровно ту же one-liner-команду через subprocess против
    локального мок-HTTPServer (200/301/404/500/503) и неиспользуемого
    порта. URL подменяется через `_retarget`, чтобы тестировать живой
    код из compose, а не его копию.

ADR: docs/work-items/ET-015/06-adr/ADR-020-healthcheck-via-python-urllib.md
CHANGELOG: запись в [Unreleased] / Fixed.

Refs: ET-015

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-05 15:32:34 +00:00

46 lines
1.3 KiB
YAML

version: "3.8"
services:
app:
build: .
ports:
- "5556:5556"
volumes:
- ./data:/app/data
- ./src/web:/app/src/web
- ./config:/app/config:ro
environment:
- DATABASE_URL=sqlite:///./data/enduro.db
- DATA_PATH=/app/data/centralfederal.sqlite
- TILES_DIR=/app/data/terrain
- TERRAIN_DIR=/app/data/terrain
- STATIC_DIR=/app/src/web
- OSRM_URL=http://172.22.0.1:5559
- PORT=5556
- GPS_TRACKS_DB_PATH=/app/data/gps_tracks.sqlite
- GPS_SOURCES_CONFIG=/app/config/gps_sources.yaml
- GPS_REGIONS_CONFIG=/app/config/gps_regions.yaml
healthcheck:
test:
- "CMD"
- "python"
- "-c"
- "import urllib.request,sys; sys.exit(0 if urllib.request.urlopen('http://localhost:5556/api/health', timeout=3).status == 200 else 1)"
interval: 30s
timeout: 5s
retries: 3
start_period: 20s
gps-collector:
build: .
profiles: ["batch"]
volumes:
- ./data:/app/data
- ./config:/app/config:ro
- /var/log/enduro-trails:/var/log/enduro-trails
environment:
- GPS_TRACKS_DB_PATH=/app/data/gps_tracks.sqlite
- GPS_SOURCES_CONFIG=/app/config/gps_sources.yaml
- GPS_REGIONS_CONFIG=/app/config/gps_regions.yaml
command: ["python", "-m", "scripts.gps_collect"]
restart: "no"