x-app-env: &app-env POSTGRES_DSN: postgresql+asyncpg://ledgerline:ledgerline@postgres:5432/ledgerline REDIS_URL: redis://redis:6379/0 GATEWAY_URL: http://gateway:8000 LEDGER_URL: http://ledger:8001 FRAUD_URL: http://fraud:8002 SANCTIONS_URL: http://sanctions:8003 INSIGHTS_URL: http://insights:8004 NOTIFIER_URL: http://notifier:8005 # Merged into the Resource by Resource.create(). deploy.sh sets DEPLOY_HASH # to the deployed git SHA; anything else (local runs) is "dev". OTEL_RESOURCE_ATTRIBUTES: service.version=${DEPLOY_HASH:-dev} x-app-build: &app-build build: context: . dockerfile: Dockerfile x-app-volumes: &app-volumes volumes: - ./common:/app/common - ./services:/app/services - ./db:/app/db - ./scripts:/app/scripts x-app-depends: &app-depends depends_on: postgres: condition: service_healthy redis: condition: service_healthy services: postgres: image: postgres:16-alpine # max_connections=300: five separate services each keep their own # SQLAlchemy pool (several sized up to pool_size=20+max_overflow=10), # all against this one Postgres instance -- comfortably clears the # default 100 under concurrent load instead of silently rationing # connections in a way that looks like an unrelated pathology. command: - postgres - -c - shared_preload_libraries=pg_stat_statements - -c - pg_stat_statements.track=all - -c - pg_stat_statements.max=10000 - -c - max_connections=300 environment: POSTGRES_USER: ledgerline POSTGRES_PASSWORD: ledgerline POSTGRES_DB: ledgerline ports: - "5432:5432" healthcheck: test: ["CMD-SHELL", "pg_isready -U ledgerline -d ledgerline"] interval: 3s timeout: 3s retries: 20 volumes: - pgdata:/var/lib/postgresql/data redis: image: redis:7-alpine ports: - "6379:6379" healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 3s timeout: 3s retries: 20 gateway: <<: [*app-build, *app-depends] volumes: - ./common:/app/common - ./services:/app/services - ./db:/app/db - ./scripts:/app/scripts environment: <<: *app-env SERVICE_NAME: gateway command: uvicorn services.gateway.app:app --host 0.0.0.0 --port 8000 --reload --no-access-log ports: - "8000:8000" healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8000/healthz"] interval: 5s timeout: 3s retries: 10 start_period: 10s ledger: <<: [*app-build, *app-depends] volumes: - ./common:/app/common - ./services:/app/services - ./db:/app/db - ./scripts:/app/scripts environment: <<: *app-env SERVICE_NAME: ledger command: uvicorn services.ledger.app:app --host 0.0.0.0 --port 8001 --reload --no-access-log ports: - "8001:8001" healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8001/healthz"] interval: 5s timeout: 3s retries: 10 start_period: 10s fraud: <<: [*app-build, *app-depends] volumes: - ./common:/app/common - ./services:/app/services - ./db:/app/db - ./scripts:/app/scripts environment: <<: *app-env SERVICE_NAME: fraud command: uvicorn services.fraud.app:app --host 0.0.0.0 --port 8002 --reload --no-access-log ports: - "8002:8002" healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8002/healthz"] interval: 5s timeout: 3s retries: 10 start_period: 10s sanctions: <<: [*app-build, *app-depends] volumes: - ./common:/app/common - ./services:/app/services - ./db:/app/db - ./scripts:/app/scripts environment: <<: *app-env SERVICE_NAME: sanctions OTEL_SERVICE_NAME: sanctions OTEL_EXPORTER_OTLP_ENDPOINT: https://otlp.vione.cloud OTEL_EXPORTER_OTLP_PROTOCOL: http/protobuf OTEL_TRACES_EXPORTER: otlp OTEL_METRICS_EXPORTER: none OTEL_LOGS_EXPORTER: none env_file: - .env.observability command: uvicorn services.sanctions.app:app --host 0.0.0.0 --port 8003 --reload --no-access-log ports: - "8003:8003" healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8003/healthz"] interval: 5s timeout: 3s retries: 10 start_period: 10s insights: <<: [*app-build, *app-depends] volumes: - ./common:/app/common - ./services:/app/services - ./db:/app/db - ./scripts:/app/scripts environment: <<: *app-env SERVICE_NAME: insights command: uvicorn services.insights.app:app --host 0.0.0.0 --port 8004 --reload --no-access-log ports: - "8004:8004" healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8004/healthz"] interval: 5s timeout: 3s retries: 10 start_period: 10s notifier: <<: [*app-build, *app-depends] volumes: - ./common:/app/common - ./services:/app/services - ./db:/app/db - ./scripts:/app/scripts environment: <<: *app-env SERVICE_NAME: notifier command: uvicorn services.notifier.app:app --host 0.0.0.0 --port 8005 --reload --no-access-log ports: - "8005:8005" healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8005/healthz"] interval: 5s timeout: 3s retries: 10 start_period: 10s audit: <<: [*app-build, *app-depends] volumes: - ./common:/app/common - ./services:/app/services - ./db:/app/db - ./scripts:/app/scripts environment: <<: *app-env SERVICE_NAME: audit command: python -m services.audit.worker volumes: pgdata: