Lesson 10 · Senior containers & local dev
Readiness, healthchecks, and startup order
The senior version of depends_on: what failures you are actually preventing, and why one gate can be smarter than twenty-five little guesses.
Your win: explain why started is not ready, what wait-for-it-service is really protecting against, and how to reason about readiness gates without cargo-culting them.
The easy answer vs the useful answer
The easy answer is: “use healthchecks.” The useful answer is: “use a health signal that matches the failure you are trying to avoid.” That is the senior shift in this lesson.
If a dependency has started but cannot actually serve requests yet, the stack still breaks. So the real topic is not startup order in the abstract. It is startup order tied to concrete failure modes.
Why startup races feel random when they are not
Most local-boot failures are not “Docker is flaky.” They are dependency timing failures: Postgres has not accepted connections yet, Unleash is not healthy yet, or another service assumes an endpoint exists before it actually does.
Once you learn to see those as dependency races, the whole topic becomes calmer. You stop staring at “container is up” and start asking “is the dependency genuinely usable yet?”
Why this repo uses one gate container
Instead of putting bespoke readiness logic on every application service, the repo centralizes infra readiness in wait-for-it-service. That gate checks DB and Unleash health, and the application services wait on that one shared signal before starting.
The design is not magical. It is just legible. One place defines the infra-ready contract, and the rest of the service stack can depend on it.
local/docker-compose.service.macos.yaml defines wait-for-it-service and the condition: service_healthy dependency chain. local/docker-compose.infra.yaml shows the DB and other infra-side health signals that make the gate meaningful.
Compose startup order docs
This is the official explanation of the started-vs-ready distinction. Read it, then come back and notice how the repo turns that general rule into one concrete gate pattern.
→ Docker — Control startup order
→ local/docker-compose.service.macos.yaml
Check yourself (from memory)
Q1. The best reason to add a readiness gate is…
wait-for-it-service catches — and which it does not? Ask me.Sources. Compose startup-order docs; in-repo compose files.