jonnifyelixir
F7 · Deploy to Fly / F7.5 · Portal is live

F7 · the capstone · module 5

Portal is live

Every preceding module gated on its own slice — a built image, a resolved host, a migrated table, a clean release event. None of those, alone, proves the whole is live: the four faults stack, and three of them produce the identical boot symptom, so a green slice can sit on top of a still-broken composition. The chapter is done only when a public 200 is observed end to end: curl -fsS https://echo-portal.fly.dev/health returns the body ok, exit 0. That is the terminal gate — an observed prod fact, not a config that looks right. The probe’s exit code is the acceptance, because the only thing that distinguishes “deployed correctly” from “deployed wrong” is a live response returned over the public internet. This module supplies that terminal proof, and then the runbook and the day-2 surface that keep the endpoint live after the first boot.

Three dives: the prod standing-liveness verification, where curl -fsS’s exit code is the gate; the four-gotcha triage runbook as a symptom-to-fix decision tree, with the cross-machine discriminator that separates the two faults that crash with the identical :nxdomain; and the day-2 operations — logs, status, proxy-and-psql inspection, re-migration idempotency, and rollback.

Liveness is the acceptance

The terminal gate is one command, and its exit code is the verdict. curl -fsS https://echo-portal.fly.dev/health hits the :health route, declared outside the :browser pipeline so it needs no session or CSRF token; the action answers send_resp(conn, 200, "ok") — a 200 with the literal body ok, no domain call. The flags carry the meaning: -f makes curl exit non-zero on any non-2xx, -sS stays quiet but still prints a real error, so the command’s exit status alone separates a live endpoint from a dead one. Select a response to see what the gate returns.

curl -fsS · the exit code is the gate

PROBE curl -fsS …/health the public endpoint RESPONSE 200 · ok exit 0 VERDICT PORTAL LIVE curl -fsS …/health >/dev/null && echo "PORTAL LIVE" || echo "PORTAL DOWN"

A value that “looks right” never fails a build — a wrong value fails a boot. The only proof that the composition is live is a 200 returned over the public internet, and the Operator’s deploy, not an ephemeral boot, is what keeps the machine durable.

From symptom to fix

When a boot fails, the chapter’s four-gotcha spine becomes a decision tree: observe the symptom in fly logs, map it to the gotcha, apply the fix, and route the change to the module that owns it. The faults stack — each fix surfaces the next — and three of the four share the :nxdomain symptom, so the tree leans on one decisive discriminator: resolve the database name from another running machine in the org. Select a symptom to walk it to its fix.

The triage runbook · select a boot symptom

SYMPTOM · fly logs :nxdomain on the DB host but the name resolves from another machine discriminator: getent hosts <db>.internal GOTCHA & FIX gotcha 3 — the decisive fix socket_options: [:inet6] on Portal.Repo an A-query on an AAAA-only name OWNER F7.2

Three of the four faults emit the identical :nxdomain; one command tells them apart. The runbook does not memorize symptoms — it routes each one to the module that owns the fix, so a boot failure is diagnosable from a known symptom to a known fix in a known place.

Three deep dives

In order: the prod standing-liveness criterion and why the probe’s exit code is the acceptance; the four-gotcha triage runbook as a full decision tree, with both discriminators; and the day-2 operations the first bring-up forced into existence — reading logs, inspecting the database over a proxy, and the idempotent re-migration and rollback paths.

F7.5.1
Liveness verification
The prod standing-liveness criterion — curl -fsS https://echo-portal.fly.dev/health → ok (the :health route, no session or CSRF) plus the /courses route smoke — and why the -fsS exit code is the gate, not a config inspection.
F7.5.2
The four-gotcha triage runbook
The spine table as a symptom → gotcha → fix → owning-module decision tree, with the cross-machine getent hosts <db>.internal discriminator that separates gotcha 2 from gotcha 3 when both crash with the same :nxdomain.
F7.5.3
Day-2 operations
fly logs (a stopped machine has no live tail), fly status/releases, fly proxy + psql on the writable primary, and the idempotent Portal.Release.migrate/0 and rollback/2 paths — with no command printing a secret.

F7.1–F7.4 gated each slice

a built image, a resolved host, a migrated table, a clean release — each green on its own, separately verified.

F7.5 proves the whole

one observed curl -fsS …/health → ok shows the four slices compose into a running system.

Start with liveness verification, then the four-gotcha runbook, then day-2 operations. This is the capstone of F7 — there is nothing after it. It verifies the composition that F7.4 — fly.toml & the deploy mechanics ships, and turns the chapter’s four-gotcha spine into a runbook for keeping the endpoint live.

References

The probe whose exit code is the gate, the health check the proxy runs, the logs where a gotcha surfaces, the proxy path to the production database, and the idempotent migrator behind the re-migration.

Sources

Related in this course