# Local HA smoke-test harness for claudemesh broker. # # 2 broker replicas behind Traefik with sticky sessions, single Postgres. # Boot with: # docker compose -f packaging/docker-compose.ha-local.yml up --build # # Then: # claudemesh launch --name A --join --broker ws://localhost/ws # # kill a container: # docker compose -f packaging/docker-compose.ha-local.yml kill broker-a # # observe that sessions reconnect to broker-b automatically # # Known gaps (see .artifacts/specs/2026-04-15-broker-ha-statelessness-audit.md): # - streamSubscriptions are per-node (pub on A, sub on B won't work) # - audit hash chain may fork under concurrent writes # - meshClocks may double-fire if both nodes think they own a clock services: db: image: postgres:16-alpine environment: POSTGRES_USER: claudemesh POSTGRES_PASSWORD: ha_smoke_test POSTGRES_DB: claudemesh volumes: - ha-pgdata:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U claudemesh"] interval: 2s timeout: 3s retries: 10 broker-a: &broker-template build: context: ../ dockerfile: apps/broker/Dockerfile environment: NODE_ENV: production DATABASE_URL: postgres://claudemesh:ha_smoke_test@db:5432/claudemesh BROKER_PORT: 7900 BROKER_ENCRYPTION_KEY: "0000000000000000000000000000000000000000000000000000000000000000" BROKER_LEGACY_AUTH: "1" BROKER_PUBLIC_URL: http://localhost BROKER_WS_URL: ws://localhost/ws MAX_CONNECTIONS_PER_MESH: "200" depends_on: db: condition: service_healthy labels: - "traefik.enable=true" - "traefik.http.routers.broker.rule=Host(`localhost`) || PathPrefix(`/`)" - "traefik.http.services.broker.loadbalancer.sticky.cookie=true" - "traefik.http.services.broker.loadbalancer.sticky.cookie.name=cm_node" - "traefik.http.services.broker.loadbalancer.server.port=7900" broker-b: <<: *broker-template traefik: image: traefik:v3.0 command: - --providers.docker=true - --providers.docker.exposedbydefault=false - --entrypoints.web.address=:80 - --api.insecure=true ports: - "80:80" - "8080:8080" # Traefik dashboard volumes: - /var/run/docker.sock:/var/run/docker.sock:ro depends_on: - broker-a - broker-b volumes: ha-pgdata: