Skip to content

fix(fly): auto_start workers — rolling deploys were leaving them stopped#3374

Merged
bokelley merged 2 commits into
mainfrom
bokelley/fly-worker-auto-start
Apr 28, 2026
Merged

fix(fly): auto_start workers — rolling deploys were leaving them stopped#3374
bokelley merged 2 commits into
mainfrom
bokelley/fly-worker-auto-start

Conversation

@bokelley

Copy link
Copy Markdown
Contributor

Summary

Production workers on adcp-docs have been sitting in stopped state with check status \"the machine hasn't started\" since the readers PR (#3352) deploy. The worker process group's lifecycle was never opted into Fly's auto_start_machines path the way [http_service] is for web — so a rolling deploy creates new worker machines but never starts them.

This is what prevented the full property-registry-unification chain (#3274/#3314/#3312/#3352) from being exercised in production: the periodic crawler that calls PublisherDatabase.upsertAdagentsCache only runs on workers (every 30 min for the catalog queue, every 6h for buying agents), and workers were dead.

Verified by manually firing POST /api/registry/crawl-request for mamamia.com.au: writer projected one row, trigger emitted authorization.granted, UNION reader returned the catalog row through /api/registry/lookup/agent/.../domains. Full chain works — workers just weren't running it.

Change

Replace the bare [[checks]] block for worker-health with a [[services]] block:

  • processes = [\"worker\"] — scopes to the worker process group
  • auto_start_machines = true — same lifecycle hook [http_service] uses for web
  • min_machines_running = 2 — Fly will keep two workers alive
  • No [[services.ports]] block — no external traffic; the internal_port is only used by the http_check
  • [[services.http_checks]] replaces the prior bare check

fly config validate passes (warning about missing ports is stale documentation about a Feb 2024 deprecation that didn't actually hard-fail).

Test plan

  • Merge → next deploy creates worker machines that auto-start (no manual fly machine start needed).
  • Periodic catalog crawl resumes (logs: "Periodic catalog domain crawl started").
  • After 30 min, /api/registry/feed?types=authorization.* shows new events from the queue draining.
  • If a deploy fails health checks, workers don't get stuck in stopped.

Rollback

Revert this PR; workers fall back to manual start. Either run fly machine start <id> for each, or fly scale count worker=2 --process=worker.

🤖 Generated with Claude Code

…ers stopped)

The worker process group has no auto_start_machines path. http_service
covers web, but the bare [[checks]] block for worker-health only keeps
running workers from being killed — it doesn't start a stopped worker.

Symptom: rolling deploys create new worker machines but never start
them. Both worker machines on adcp-docs sat in 'stopped' state with
check status "the machine hasn't started" since the readers PR deploy
(2026-04-28 06:51 UTC), which means the periodic crawler that calls
publisherDb.upsertAdagentsCache (every 30 min for the catalog queue,
every 6h for buying agents) never ran in production after the PR 4b
chain merged. The full property-registry-unification chain
(#3274/#3314/#3312/#3352) was therefore unexercised in prod until a
manual /api/registry/crawl-request triggered it.

Replace the bare [[checks]] block with a [[services]] block targeting
processes=["worker"] with auto_start_machines=true and
min_machines_running=2 — same lifecycle hooks http_service uses for
web. No [[services.ports]] block, so workers stay private. The
http_check inside the services block replaces the prior bare check.

Refs #3177 (this is the gap that prevented prod verification of the
4b chain).
EOF
@bokelley bokelley merged commit 7380b36 into main Apr 28, 2026
12 checks passed
@bokelley bokelley deleted the bokelley/fly-worker-auto-start branch April 28, 2026 07:08
bokelley added a commit that referenced this pull request May 18, 2026
PR #3374's `auto_start_machines = true` + `min_machines_running = 1` on
the worker `[[services]]` block are inert without a `[[services.ports]]`
entry — Fly only enforces those flags via fly-proxy, and a service with
no ports isn't routed through fly-proxy. Rolling deploys that leave the
worker `stopped` had no recovery path; the watchdog from PR #4358
observed the failure but couldn't act on it. Today's 04:31 UTC alert
required a manual `fly machine start`.

On probe failure the watchdog now calls the Fly Machines API, finds any
worker machines in `stopped` state, and starts them. The recovered
machine surfaces as a successful probe on the next tick. If start
didn't help (real crashloop), failures keep climbing and the alert
still fires at the threshold.

Requires the `FLY_API_TOKEN` secret on the app — without it, recovery
is a no-op and behavior matches PR #4358 exactly. Mint with
`fly tokens create deploy -a adcp-docs` and set via `fly secrets set`.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
bokelley added a commit that referenced this pull request May 18, 2026
* docs(fly): correct misleading worker autostart comment (#4723)

The fly.toml block for the worker process group claimed that adding
`auto_start_machines = true` + `min_machines_running = 1` opted workers
into Fly's autostart lifecycle. It does not — per Fly docs, those flags
are enforced through fly-proxy, and a `[[services]]` block without
`[[services.ports]]` doesn't get fly-proxy routing. The settings are
inert; the block still earns its keep by attaching the http_check.

The actual recovery gap (rolling deploys can leave the worker `stopped`
with no automatic restart) is tracked in #4723.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(watchdog): active recovery for stopped workers (#4723)

PR #3374's `auto_start_machines = true` + `min_machines_running = 1` on
the worker `[[services]]` block are inert without a `[[services.ports]]`
entry — Fly only enforces those flags via fly-proxy, and a service with
no ports isn't routed through fly-proxy. Rolling deploys that leave the
worker `stopped` had no recovery path; the watchdog from PR #4358
observed the failure but couldn't act on it. Today's 04:31 UTC alert
required a manual `fly machine start`.

On probe failure the watchdog now calls the Fly Machines API, finds any
worker machines in `stopped` state, and starts them. The recovered
machine surfaces as a successful probe on the next tick. If start
didn't help (real crashloop), failures keep climbing and the alert
still fires at the threshold.

Requires the `FLY_API_TOKEN` secret on the app — without it, recovery
is a no-op and behavior matches PR #4358 exactly. Mint with
`fly tokens create deploy -a adcp-docs` and set via `fly secrets set`.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant