services: # -- NATS Server ---------------------------- nats: image: nats:latest profiles: ["nats"] ports: - "4222:4222" - "8222:8222" command: > --auth ${NATS_TOKEN:-realsense-dev-token} --http_port 8222 restart: unless-stopped healthcheck: test: ["CMD", "nats-server", "--help"] interval: 5s timeout: 3s retries: 3 start_period: 5s # -- Backend -------------------------------- backend: build: context: . dockerfile: Dockerfile # network: host so that build-time apt/git/pip can reach the # tinyproxy running on the host at localhost:8888. network: host privileged: true ports: - "${API_PORT:-8878}:8878" devices: - "/dev/bus/usb:/dev/bus/usb" volumes: - ./images:/app/images - ./models:/app/models:ro # mscli + master_service socket so the container can stop the # Unitree video_hub_pc4 service (it holds /dev/video4 — the D435i # V4L2 node — and would otherwise make Open() fail with EBUSY). - /unitree/sbin/mscli:/unitree/sbin/mscli:ro - /unitree/var/run/master_service.sock:/unitree/var/run/master_service.sock entrypoint: - bash - -c - | /unitree/sbin/mscli stopservice video_hub_pc4 >/dev/null 2>&1 || true sleep 2 ( while sleep 10; do /unitree/sbin/mscli stopservice video_hub_pc4 >/dev/null 2>&1 || true; done ) & exec /app/entrypoint.sh env_file: .env depends_on: nats: condition: service_healthy required: false restart: unless-stopped labels: # autoheal monitora SOLO i container con questa label = true autoheal: "true" healthcheck: # Healthcheck "vero": fallisce se camera_open != true. # Usa /api/health (pubblico, no API key) che già ritorna camera_open. # 4 retry × 15s ⇒ ~1 min di stato cattivo prima dell'autoheal restart. test: - CMD - python3 - -c - | import urllib.request, json, sys try: r = urllib.request.urlopen('http://localhost:8878/api/health', timeout=3) d = json.loads(r.read()) sys.exit(0 if d.get('data', {}).get('camera_open') else 1) except Exception: sys.exit(1) interval: 15s timeout: 5s retries: 4 start_period: 30s # -- Autoheal ------------------------------- # Monitora i container con label `autoheal=true` e li restarta automaticamente # quando Docker li marca "unhealthy". Risolve il caso "pyrealsense2 SDK stuck". autoheal: image: willfarrell/autoheal:latest container_name: autoheal-d435 restart: always environment: AUTOHEAL_CONTAINER_LABEL: autoheal AUTOHEAL_INTERVAL: 10 AUTOHEAL_START_PERIOD: 30 volumes: - /var/run/docker.sock:/var/run/docker.sock:ro # -- Frontend React Dev (hot reload) -------- frontend-dev: image: node:20-alpine working_dir: /app volumes: - ./src/frontend/react:/app - /app/node_modules command: sh -c "npm ci && npm run dev -- --host 0.0.0.0" ports: - "5173:5173" profiles: [dev]