Applies to: container deployments of GoBridge (ECS, Kubernetes, plain Docker). Audience: operators rolling image versions and anyone running a SQLite store in a container. Risk: high for SQLite on ephemeral storage — a scale-in or redeploy can drop undelivered messages silently. Read the durability section before you scale.
Gate on readiness before shifting traffic — do not trust /health alone,
which stays green before sessions connect
(health-and-shutdown.md#health-endpoints):
curl -s "http://<host>:8081/api/v1/monitor/ready?level=subscribed" # 200 → every subscription acked
Redeploy the previous image digest. Because the process exits non-zero on an unrecoverable startup or runtime fault, a task that fails to start on the new image is restarted by the orchestrator rather than left wedged (health-and-shutdown.md#exit-codes). If a bad config rode along with the image, revert it with the transactions API — see Config Rollback.
Deploy by digest (myregistry.example.com/gobridge@sha256:...), never by tag.
The GoBridge project publishes no image: you build and push your own — the
repository root Dockerfile for the AWS profile binary,
deployment/kubernetes/Dockerfile for the reference binary — so the digest that
push prints is the authoritative version-to-image association. Record it
alongside the GoBridge version it contains. A task definition or pod spec that
names a tag can change under you on the next deploy. The same rule applies to
the base images in the Dockerfile (FROM ...@sha256:...). To read back the
digest behind a tag you pushed:
docker buildx imagetools inspect myregistry.example.com/gobridge:<tag> \
--format ''
Rolling back is redeploying the previous digest. On AWS, where a CDK facade
with no Image set builds the image during cdk deploy, roll back by
deploying the previous version of your CDK app: the facade then builds from the
profile module version that app depends on
(pin images by digest).
A containerized SQLite store must live on a durable volume. The SQLite outbox, lease, DLQ, and managed-subscription stores keep delivery-critical records on disk. If that disk is the container’s ephemeral filesystem, stopping or replacing the task destroys any records it still holds — silent message loss with no error.
The AWS CDK profile guards against this: the Phase-1 validator rejects any store
path that is not under the EFS mount root, returning ErrStorePathOutsideMount.
Operators wiring their own Kubernetes or Docker deployment get no such guard.
Put every SQLite store path on a persistent volume (a PersistentVolumeClaim, a
bind-mounted host path, or a network filesystem), never on the container’s
writable layer or an emptyDir.
Scaling in a task whose SQLite outbox still holds undelivered records on ephemeral storage loses them. Before you remove or replace an instance:
direct_hold).OutboxDepth reaches 0
(monitoring.md#key-metrics).
Set MaxOutboxDepth so OutboxDepth reports the true backlog rather than a
saturating batch-size floor — otherwise a deep backlog is invisible
(monitoring.md#key-metrics).SQLiteStoreUnhealthy (entity=outbox) is a fatal storage fault — disk full,
corruption, read-only, or not-a-database. Alert on it directly; it means free
disk or restore the file, and records stay durable until you do
(monitoring.md#key-metrics).
The SQLite store is a single file per store (plus the WAL/SHM sidecars) on the durable volume. To back it up consistently:
-wal and -shm sidecars, or use
sqlite3 <file> ".backup <dest>" for an online snapshot.To restore, place the file back on the durable volume at the configured store path before the task starts, then start the task. A restored outbox replays its undelivered records on first drain.