Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Fix openstatus-api auto_suspend + min_machines_running=1 makes the public API a single point of failure during traffic lulls - #2701

Open
polylane[bot] wants to merge 1 commit into
mainfrom
polylane/autofix/rg5v388gd0tv
Open

Fix openstatus-api auto_suspend + min_machines_running=1 makes the public API a single point of failure during traffic lulls#2701
polylane[bot] wants to merge 1 commit into
mainfrom
polylane/autofix/rg5v388gd0tv

Conversation

@polylane

@polylane polylane Bot commented Sep 10, 2026

Copy link
Copy Markdown
Contributor

Fixes: openstatus-api auto_suspend + min_machines_running=1 makes the public API a single point of failure during traffic lulls

The openstatus-api Fly fleet is configured to suspend idle machines toward min_machines_running = 1. During traffic lulls, machines in a region suspend and requests landing in that window are rejected with 503 by the edge, and the 2-region fleet collapses to a single serving machine — a single point of failure that escalates to a full outage when a lull coincides with a degraded instance. This change turns auto-stop off and raises the machine floor to 2, so one machine stays serving in each region.

What caused this

Affected: acc_01b058a86001tjsvwd8nll0s · severity medium

What changed

  • apps/server/fly.toml: set auto_stop_machines = "off" and min_machines_running = 2 in the [http_service] block so the public API never suspends below one machine per region.

Why it's safe

  • No runtime code, schema, or interface changes: the diff is two keys in a deploy config file that Fly applies on the next flyctl deploy; it cannot break the application build or a request path.
  • Raising min_machines_running to 2 costs one extra machine-hour per region (a shared-4/1GB VM in iad and ams) but restores a real per-region serving machine instead of a suspendable single machine; no new external dependency is introduced.
  • auto_stop_machines = "off" matches the repo's own convention for always-on public workloads (workflows, checker, private-location), so the behavior is already proven in this fleet.
  • The health check (GET /ping) and concurrency limits are untouched, so Fly's existing readiness gating continues to apply.

Validation

  • python3 -c "import tomllib; ..." on apps/server/fly.toml: parses, autostop: off | min: 2
  • pnpm format:check: 0 errors (38 pre-existing warnings, none in the changed file)
  • not run: pnpm check:docs and turbo run check: deno is not installed in the sandbox, so the Deno-based package checks fail with spawn ENOENT — unrelated to this TOML-only change; no TypeScript or Deno file was touched
Root cause and scoping notes

Root cause

The public API's Fly config (apps/server/fly.toml, deployed verbatim by .github/workflows/deploy.yml via flyctl deploy --config apps/server/fly.toml) sets auto_stop_machines = "suspend" with min_machines_running = 1. Live machine 683e3d1c400d78 confirms the deployed fleet still carries "autostop":"suspend","autostart":true,"min_machines_running":1.

Mechanism: during a traffic lull, Fly proxy-initiated suspension cycles begin (documented 02:40–04:10Z on 2026-09-10, ~30s suspend→cancel→start→uncordon across all four machines), and requests landing in a suspend window get 503 from the edge. With only one machine kept running fleet-wide, a single region's suspension leaves one machine serving the whole 2-region (iad + ams) fleet — a single point of failure. This produced a documented 3.56% edge server-error deviation and contributed to the 03:20–05:19Z episode where monitor 771 saw 503s from all 18 Fly regions.

The fix disables auto-stop and raises the floor to 2 (one per region), matching the sibling always-on apps in this repo (apps/workflows/fly.toml, apps/checker/fly.toml, apps/private-location/fly.toml all use auto_stop_machines = "off"). This removes the suspend-cycle race at its producer rather than tolerating the resulting 503s.

Causal chain
  • Signal (metric): edge server-error ratio deviation 3.56% (iss_0897dc84c001yiyjx68tio1c) and 03:20-05:19Z 503 episode; monitor 771 raw checks 503s from all 18 Fly regions
  • Surfacing site: openstatus-api at Fly edge routing (18 regions), observed via OpenStatus API monitor and edge metrics
  • Mechanism: Fly auto-stop suspends idle machines toward min_machines_running=1; requests landing in a suspend window or during the ~30s suspend/cancel/start/uncordon cycle get 503 from the edge, and a single region's suspension leaves only one machine serving the 2-region fleet.
  • Producer: apps/server/fly.toml [http_service] block, instance machine 683e3d1c400d78 (iad, started) and fleet, at openstatusHQ/openstatus:apps/server/fly.toml#L21-23
  • Trigger: Traffic lulls between external monitor checks (monitor 771 probes /ping every 10m), which recur constantly.
  • What happens to the failed unit today: Requests landing in a suspend window are rejected 503 at the edge; no retry at the platform layer, the client sees a failed request.
  • Cadence check: Config is always present, so it predicts intermittent 503s at every lull, matching the two documented 09-10 events and suspend cycles visible across all four machines 02:40-04:10Z.
  • Blast radius: 18 other resource(s), 0 other tenant(s); data at risk: Public API requests are rejected (503) during suspension windows; no data loss, but availability of the whole API degrades and a lull coinciding with a degraded instance escalates to full outage.
  • Producer evidence:
    • apps/server/fly.toml lines 21-23: auto_stop_machines = "suspend", auto_start_machines = true, min_machines_running = 1
    • .github/workflows/deploy.yml deploys flyctl deploy --config apps/server/fly.toml
    • live Fly Machines API machine 683e3d1c400d78: "autostop":"suspend","autostart":true,"min_machines_running":1

Detection outcome

The edge server-error ratio deviation and suspension-induced 503s stop firing once this change deploys. The signal's producer is the auto_stop_machines = "suspend" + min_machines_running = 1 combination in apps/server/fly.toml; changing those to "off" and 2 removes the suspend cycle that generated the edge rejections, so requests no longer land in a suspend window and each region keeps a started machine serving.

Fix chosen

Chosen: cause (removes the mechanism that produces the failure): Disable auto-stop and raise min_machines_running to 2 in apps/server/fly.toml, removing the suspension mechanism that produces 503s during lulls.

Considered and not chosen:

  • loosen (raises a limit, threshold, or timeout, or widens a retry): Keep auto-stop enabled but raise min_machines_running to 2 so a machine is never suspended in a region. Not chosen: Still leaves a suspend window race during lulls for the third/fourth machines and saves nothing meaningful on a constantly-probed public API; disabling auto-stop removes the mechanism entirely.
  • suppress (silences, downgrades, or reroutes the signal without changing what produces it): Leave config as-is and treat the 503s as acceptable lull behavior. Not chosen: The 503s are real user-facing failures on the public API, documented twice on 09-10, with an evidenced path to full outage; suppressing the signal leaves the single point of failure in place.

Outcome after fix

Replaying the failing scenario with the change applied:

  • A traffic lull occurs between external monitor checks. Previously, Fly initiated a suspend cycle toward min_machines_running = 1; requests landing mid-cycle got 503 from the edge, and a region's suspension left one machine serving the fleet.
  • With auto_stop_machines = "off", no suspend cycle is initiated, so no request lands in a suspend window and the edge has a started machine in each region at all times.
  • With min_machines_running = 2, even a machine failure or a mid-deploy swap leaves one started machine per region serving, so the fleet never collapses to a single machine.
  • The 503 edge rejections that the monitor recorded (36–41s latencies, all regions, 04:02:19Z) no longer have a suspension-induced cause; the at-risk public API requests reach a started machine and are served normally.
1 file changed (+2/-2)
  • apps/server/fly.toml: modified, +2/-2

Repository conventions present in the repository: AGENTS.md, CLAUDE.md, apps/checker/AGENTS.md, apps/dashboard/AGENTS.md, apps/server/AGENTS.md, apps/status-page/AGENTS.md, apps/web/AGENTS.md, apps/workflows/AGENTS.md, packages/services/AGENTS.md, packages/ui/AGENTS.md.

Repository lint: pnpm run lint (declared in package.json) could not run in the sandbox because its tool is not installed there; run it before merging.

view-autofix view-investigation view-issue


Generated by Polylane.

Review in cubic

@vercel

vercel Bot commented Sep 10, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

3 Skipped Deployments
Project Deployment Actions Updated
openstatus-dashboard Skipped Skipped Sep 10, 2026 4:37pm UTC
openstatus-status-page Skipped Skipped Sep 10, 2026 4:37pm UTC
openstatus-web Skipped Skipped Sep 10, 2026 4:37pm UTC

Request Review

@vercel
vercel Bot temporarily deployed to Preview – openstatus-dashboard September 10, 2026 16:37 Inactive
@vercel
vercel Bot temporarily deployed to Preview – openstatus-status-page September 10, 2026 16:37 Inactive
@vercel
vercel Bot temporarily deployed to Preview – openstatus-web September 10, 2026 16:37 Inactive
@polylane polylane Bot added polylane severity:medium Polylane autofix severity: medium labels Sep 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

polylane severity:medium Polylane autofix severity: medium

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants