Adom Blue-Green

Install?

Zero-failed-request deploys for any Adom service container: an nginx front door, blue and green slots, a flip only when the new build reports ready at the new commit, and the old slot stopped only after it has served every request it accepted.

adom-wiki pkg install adom/adom-bluegreen

Latest: v0.1.1, published

Contents

README

markdown

adom-bluegreen

Deploy a service container without failing a single request.

Most of our service containers deploy the same way. A watchdog notices a new commit on main, kills the process and starts the new one. Everything that calls the service fails until the new process has warmed up. For Component Ocean that took 60–120 seconds per push. For anything production-dependent that is not acceptable: the bar is zero failed requests, not a short gap.

adom-bluegreen is the setup that got Component Ocean there, packaged so any service container can use it.

Component Ocean, live requests during the deploy failed
automatic deploy (cron picked up the push) 1,372 0
manual deploy 2,365 0
kit self-test: deploy under load, plus a refused broken build 13,368 0

The idea

 public URL ──> :3456  nginx  (the front door; it reloads, it never restarts)
                    ├── :3457  blue   slot  = git worktree at the commit being served
                    └── :3458  green  slot  = git worktree at the next commit, warming up
  1. Warm the new version next to the old one. A new commit starts in the idle slot while the live slot keeps serving.
  2. Switch only when the new version says it's ready, at the right commit. Each service answers GET /ready with 200 {"ready":true,"git_sha":...,"inflight":n} once it is fully warm. If the new slot never gets there, it is never served, and the old one keeps going.
  3. Switch without closing the door. nginx reloads its config while keeping the listening socket. New requests go to the new slot, and requests already in progress finish on the old one.
  4. Let the old version finish before it stops. The old slot is stopped only when its inflight count has been 0 for 5 seconds, so every request it accepted gets its answer.

Using it on your service

  1. Add the /ready contract. examples/ has copy-ready versions for Bun, Node and Python: about 15 lines, including an in-flight counter.
  2. Write a small config (examples/service.conf.example): name, repo, branch, three ports, the start command, and which gitignored paths (such as data/) both slots share.
  3. Run scripts/install.sh your.conf. It checks the config, installs nginx and schedules the watchdog.
  4. Prove it: run scripts/probe.sh against your service while you push a commit. It must end with 0 failed.

Before relying on it on a new container, run tests/selftest.sh. It performs a real deploy of a throwaway app on spare ports and must report 10 passed, 0 failed.

The full guide, including operating it, rolling back and adopting a port a service already uses, is in SKILL.md. It installs as a skill, so any Claude or Codex session can set this up for you.

What we learned the hard way

Each item below failed once while this was built. The kit handles all of them, and the reasons are written into the code:

  • A process that inherits the watchdog's lock holds it forever. Every later run exits silently and deploys just stop, with no error anywhere. It happened twice.
  • $! is the wrapper shell, not your server. Kill the wrong one and the old server keeps its port, so the next deploy can't start.
  • Two processes can't share a port. Any handoff of the public port is a gap, so the front door is never replaced while it serves. nginx changes by reload instead.
  • "The port is open" isn't "ready". The first version would have switched traffic before a search index had loaded.
  • Containers can't do the kernel-level tricks. There's no NET_ADMIN, /proc/sys is read-only and the public port mapping can't be re-pointed. That's why this is nginx-based.

Status

Proven on Component Ocean. The next step is making it the standard way our service containers deploy. If you adopt it on your service, run the probe and add your numbers here.