Files
LedgerLine/docker-compose.yml
T
Movses AslanyanandClaude Opus 5.5 ec6ddb6a26 Instrument SQLAlchemy in every service with a database
sanctions, notifier, ledger, insights and audit now call setup_telemetry
and instrument their engines with one SQLAlchemyInstrumentor call per
process (a second instrument() call is ignored, leaving that engine with
connect spans only). ledger and insights pass both their normal and
starved engines. The FastAPI services also get the server span, with the
same /healthz and receive/send exclusions as sanctions.

Compose: OTEL_SEMCONV_STABILITY_OPT_IN=http,database for the stable
attribute names, the OTLP endpoint moves to the shared env, and the four
newly instrumented services get the auth header from .env.observability.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 10:09:57 +03:30

222 lines
5.8 KiB
YAML

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}
# Emit the stable semantic-convention names (http.request.method, url.path,
# db.query.text, ...) instead of the instrumentations' legacy defaults.
OTEL_SEMCONV_STABILITY_OPT_IN: http,database
OTEL_EXPORTER_OTLP_ENDPOINT: https://otlp.vione.cloud
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
env_file:
- .env.observability
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
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
env_file:
- .env.observability
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
env_file:
- .env.observability
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
env_file:
- .env.observability
command: python -m services.audit.worker
volumes:
pgdata: