ADR 0005 — One binary, three roles, and every role migrates

ADR 0005 — One binary, three roles, and every role migrates An architecture diagram generated by Archify. One binary, three roles, each migrates · --role web|worker|all · db.Migrate at boot in every role · Architecture component One binary, three roles, each migrates --role web|worker|all · db.Migrate at boot in every role app.Role · App.Run · migrate · gates in every role · serve | work | both · the mechanism app.Role · App.Run migrate · gates in every role · serve | work | both db.Migrate · pg_advisory_lock(7240101), then the ledger · the mechanism db.Migrate pg_advisory_lock(7240101), then the ledger probes · health.Mux · /health · /ready on Server.Addr in both roles · the mechanism probes · health.Mux /health · /ready on Server.Addr in both roles TestMigrateIsIdempotent · Migrate twice · each file applied once · kept true by TestMigrateIsIdempotent Migrate twice · each file applied once Rejected: a migration job + init container · ordering incidents · rollbacks left two schemas · Architecture component Rejected: a migration job + init container ordering incidents · rollbacks left two schemas two worker replicas · share one durable · each applied the schema itself · Architecture component two worker replicas share one durable · each applied the schema itself the start command · app.New(…, Role: app.All) · a.Run(ctx) · Architecture component the start command app.New(…, Role: app.All) · a.Run(ctx) is at boot answers checked by instead of role all, migrates on the way past one manifest · kubectl set image the mechanism kept true by Legend Backend Security External

Context

  • • Before: a web image, a worker image and a migration job from one tree, plus an init container whose only purpose was to make the other two wait
  • • Most incidents were ordering: a worker before the migration, a job that had already run, a rollback that left two images on different schemas

Consequences

  • • Deploying is kubectl set image on two deployments of the same image; a worker cannot serve a stale schema, it applied the schema itself
  • • A slow migration makes every replica's boot slow, visible in the rollout; a later breaking change must choose expand-and-overlap or stop-then-migrate

Evidence

  • • go test ./kit/app -run TestWorkerRelaysAndAnswersItsProbes: the worker migrates, serves /health and /ready only, relays the outbox
  • • go test ./kit/db -run TestMigrateIsIdempotent: Migrate twice, each file applied once; a fresh database, no old-ledger conversion is claimed