version: '3.8' services: # BACKBEAT Pulse Service - Leader-elected tempo broadcaster # REQ: BACKBEAT-REQ-001 - Single BeatFrame publisher per cluster # REQ: BACKBEAT-OPS-001 - One replica prefers leadership backbeat-pulse: image: anthonyrawlins/backbeat-pulse:v1.0.4 command: > ./pulse -cluster=chorus-production -admin-port=8080 -raft-bind=0.0.0.0:9000 -data-dir=/data -nats=nats://nats:4222 -tempo=2 -bar-length=8 -log-level=info environment: # REQ: BACKBEAT-OPS-003 - Configuration via environment variables - BACKBEAT_CLUSTER_ID=chorus-production - BACKBEAT_TEMPO_BPM=2 # 30-second beats for production - BACKBEAT_BAR_LENGTH=8 # 4-minute windows - BACKBEAT_PHASE_PLAN=plan,work,review - BACKBEAT_NATS_URL=nats://nats:4222 - BACKBEAT_MIN_BPM=1 # 60-second beats minimum - BACKBEAT_MAX_BPM=60 # 1-second beats maximum - BACKBEAT_LOG_LEVEL=info # REQ: BACKBEAT-OPS-002 - Health probes for liveness/readiness healthcheck: test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:8080/healthz"] interval: 30s timeout: 10s retries: 3 start_period: 60s deploy: replicas: 1 # Single leader with automatic failover restart_policy: condition: on-failure delay: 30s # Wait longer for NATS to be ready max_attempts: 5 window: 120s update_config: parallelism: 1 delay: 30s # Wait for leader election failure_action: rollback monitor: 60s order: start-first placement: preferences: - spread: node.hostname constraints: - node.hostname != rosewood # Avoid intermittent gaming PC resources: limits: memory: 256M cpus: '0.5' reservations: memory: 128M cpus: '0.25' # Traefik routing for admin API labels: - traefik.enable=true - traefik.http.routers.backbeat-pulse.rule=Host(`backbeat-pulse.chorus.services`) - traefik.http.routers.backbeat-pulse.tls=true - traefik.http.routers.backbeat-pulse.tls.certresolver=letsencryptresolver - traefik.http.services.backbeat-pulse.loadbalancer.server.port=8080 networks: - backbeat-net - tengig # External network for Traefik # Container logging logging: driver: "json-file" options: max-size: "10m" max-file: "3" tag: "backbeat-pulse/{{.Name}}/{{.ID}}" # BACKBEAT Reverb Service - StatusClaim aggregator # REQ: BACKBEAT-REQ-020 - Subscribe to INT-B and group by window_id # REQ: BACKBEAT-OPS-001 - Reverb can scale stateless backbeat-reverb: image: anthonyrawlins/backbeat-reverb:v1.0.1 command: > ./reverb -cluster=chorus-production -nats=nats://nats:4222 -bar-length=8 -log-level=info environment: # REQ: BACKBEAT-OPS-003 - Configuration matching pulse service - BACKBEAT_CLUSTER_ID=chorus-production - BACKBEAT_NATS_URL=nats://nats:4222 - BACKBEAT_LOG_LEVEL=info - BACKBEAT_WINDOW_TTL=300s # 5-minute cleanup - BACKBEAT_MAX_WINDOWS=100 # Memory limit # REQ: BACKBEAT-OPS-002 - Health probes for orchestration healthcheck: test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:8080/healthz"] interval: 30s timeout: 10s retries: 3 start_period: 60s deploy: replicas: 2 # Stateless, can scale horizontally restart_policy: condition: on-failure delay: 10s max_attempts: 3 window: 120s update_config: parallelism: 1 delay: 15s failure_action: rollback monitor: 45s order: start-first placement: preferences: - spread: node.hostname constraints: - node.hostname != rosewood resources: limits: memory: 512M # Larger for window aggregation cpus: '1.0' reservations: memory: 256M cpus: '0.5' # Traefik routing for admin API labels: - traefik.enable=true - traefik.http.routers.backbeat-reverb.rule=Host(`backbeat-reverb.chorus.services`) - traefik.http.routers.backbeat-reverb.tls=true - traefik.http.routers.backbeat-reverb.tls.certresolver=letsencryptresolver - traefik.http.services.backbeat-reverb.loadbalancer.server.port=8080 networks: - backbeat-net - tengig # External network for Traefik # Container logging logging: driver: "json-file" options: max-size: "10m" max-file: "3" tag: "backbeat-reverb/{{.Name}}/{{.ID}}" # NATS Message Broker - Use existing or deploy dedicated instance # REQ: BACKBEAT-INT-001 - Topics via NATS for at-least-once delivery nats: image: nats:2.9-alpine command: ["--jetstream"] deploy: replicas: 1 restart_policy: condition: on-failure delay: 10s max_attempts: 3 window: 120s placement: preferences: - spread: node.hostname constraints: - node.hostname != rosewood resources: limits: memory: 256M cpus: '0.5' reservations: memory: 128M cpus: '0.25' networks: - backbeat-net # Container logging logging: driver: "json-file" options: max-size: "10m" max-file: "3" tag: "nats/{{.Name}}/{{.ID}}" # Network configuration networks: tengig: external: true # External network for Traefik backbeat-net: driver: overlay attachable: true # Allow external containers to connect ipam: config: - subnet: 10.202.0.0/24 # Persistent storage # volumes: