18.7 Run it as deployed
compose.yaml runs the whole of it: Postgres, RabbitMQ, the hub and two workers.
compose.yaml:
# Shopfront as it runs deployed: one hub, two workers, Postgres and RabbitMQ. Every secret comes
# from the environment, or from a .env file beside this one that is never committed.
# What the hub and the workers both need.
x-shopfront: &shopfront
ConnectionStrings__Shopfront: Host=database;Database=shopfront;Username=shopfront;Password=${POSTGRES_PASSWORD}
ConnectionStrings__RabbitMq: amqp://shopfront:${RABBITMQ_PASSWORD}@rabbitmq:5672
services:
database:
image: postgres:17
environment:
POSTGRES_DB: shopfront
POSTGRES_USER: shopfront
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD}
volumes:
- database:/var/lib/postgresql/data
healthcheck:
test: ["CMD", "pg_isready", "-U", "shopfront"]
interval: 5s
rabbitmq:
image: rabbitmq:4
environment:
RABBITMQ_DEFAULT_USER: shopfront
RABBITMQ_DEFAULT_PASS: ${RABBITMQ_PASSWORD:?set RABBITMQ_PASSWORD}
healthcheck:
test: ["CMD", "rabbitmq-diagnostics", "-q", "ping"]
interval: 5s
hub:
build:
context: .
dockerfile: Shopfront.Hub/Dockerfile
environment:
<<: *shopfront
# The identity provider whose tokens the hub accepts, and where the storefront is served.
Auth__Authority: ${AUTH_AUTHORITY:?set AUTH_AUTHORITY}
Auth__Audience: ${AUTH_AUDIENCE:?set AUTH_AUDIENCE}
Storefront__Origin: ${STOREFRONT_ORIGIN:?set STOREFRONT_ORIGIN}
ports:
- "8080:8080"
depends_on:
database:
condition: service_healthy
rabbitmq:
condition: service_healthy
worker:
build:
context: .
dockerfile: Shopfront.Worker/Dockerfile
environment: *shopfront
deploy:
replicas: 2
# The hub migrates the shop's schema before it serves.
depends_on:
hub:
condition: service_started
volumes:
database:A published build runs in Production unless its environment says otherwise, and nothing here says otherwise. So:
- The hub accepts only tokens from your identity provider,
Auth:AuthorityandAuth:Audience. The Development key is refused outside Development, and/dev/tokenis not mapped. - Only registered documents run, and
PersistedOperations:Requireis ignored. - The GraphQL IDE and schema download are not served.
- Development's short timeouts and fast retries are off: a run whose worker died is failed after more than an hour, not a minute, and the restock runs hourly.
Set the secrets, and start it:
export POSTGRES_PASSWORD=... RABBITMQ_PASSWORD=...
export AUTH_AUTHORITY=https://login.example.com/ AUTH_AUDIENCE=shopfront
export STOREFRONT_ORIGIN=https://shop.example.com
docker compose up -d --buildcurl -s http://localhost:8080/health/live
curl -s http://localhost:8080/health/readyHealthy
HealthyThe hub migrated both schemas and serves:
info: Microsoft.EntityFrameworkCore.Migrations[20402]
Applying migration '20261018214548_Initial'.
...
info: Trax.Effect.Broadcaster.RabbitMQ.RabbitMqTrainEventReceiver[0]
RabbitMQ receiver started on exchange trax.lifecycle, queue amq.gen-iiJgCfj_9Vb3N9nM6CyCoA.
info: Trax.Scheduler.Services.SchedulerStartupService.SchedulerStartupService[0]
Successfully seeded 3 manifest(s)
info: Trax.Api.GraphQL.PersistedOperations[0]
Persisted-operation enforcement is ON. ...EF Core logs one fail: before that, the first time: it looks for the history table before it
creates it. On a fresh database that is expected, and later starts log none.
The storefront's documents run by id, and text is refused, as in chapter 17. The catalogue has more
caps and T-shirts than it started with: the restock ran as soon as the hub scheduled it, on a
worker, which logged Received 2 deliveries.
{"data":{"discover":{"products":{"nodes":[{"sku":"CAP","name":"Cap","price":18.50,"stock":5},{"sku":"MUG","name":"Mug","price":12.00,"stock":10},{"sku":"TEE","name":"T-shirt","price":25.00,"stock":8}]}}}} 200
{"errors":[{"message":"Only persisted operations are accepted on this server.","extensions":{"code":"PERSISTED_OPERATION_REQUIRED"}}]} 400/dev/token and the GraphQL IDE answer 404. The hub also warns that ASP.NET Core keeps its
data-protection keys inside the container. Shopfront signs nothing with them, since its callers
carry bearer tokens and no cookies; a hub that adds cookie sign-in keeps those keys somewhere that
outlives the container.
SDK Reference
Deployment topologies | Move a domain data context to EF migrations | UseRabbitMq | AddTraxHealthCheck | Health and liveness | Startup refusals | UseTraxApiDashboard
Next: 18.8 The storefront