Dead-host detection + machine drain/failover - #6
Merged
Conversation
The control plane never noticed a host going away: a crashed or partitioned host kept its machines assigned forever, so apps didn't recover and the scheduler could still target a dead host. - A host monitor loop marks a host `down` after it misses heartbeats for FOLD_HOST_TIMEOUT (default 30s); the next heartbeat brings it back `up`. The scheduler already skips non-up hosts, so placement avoids it. - Draining a down host: running machines are rescheduled onto healthy hosts (volume-backed ones keep their AZ; the volume is detached from the dead host first so it can re-attach), with their stale host-local snapshot cleared so they cold-start where they land. Machines that aren't wanted-running are just unplaced. - wake() now re-places unplaced machines, so a scaled-to-zero app recovers on the next request after its host died. - `fold hosts list` shows host state (up|down). Reschedule is serialized per app (lockApp) against deploys/scale. Caveat: a live-but-partitioned host has its machines moved elsewhere; the cloud's single-attach guarantee prevents a split for volume-backed apps, but a hard partition can briefly double-run stateless copies (documented). Tests: drain reschedules a started machine to a live host, unplaces a suspended one (clearing its dead snapshot), and the monitor marks a stale host down then a heartbeat recovers it. Verified end-to-end: killed a local agent and watched the host flip down then up on restart. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Context
Last core reliability gap from the audit. The control plane never noticed a host going away — a crashed or network-partitioned host kept its machines assigned indefinitely, so apps didn't recover and the scheduler could still place new machines onto a dead host. (Now much easier to operate thanks to the structured logs from #5.)
Branched from a clean
main(no stacking).What changed
RunHostMonitorloop marks a hostdownafter it misses heartbeats forFOLD_HOST_TIMEOUT(default 30s); the next heartbeat brings it backup. The scheduler already skips non-uphosts, so placement avoids dead hosts automatically.wake()now re-places unplaced machines, so a scaled-to-zero app recovers on the next request even if its old host died.store.Heartbeatclears thedownmark; control logs the down/up transitions.fold hosts listshows hoststate(up|down).Reschedule is serialized per app (
lockApp) against concurrent deploys/scale.Caveat (documented)
A host that's alive but partitioned from control will have its machines rescheduled elsewhere. The cloud's single-attach guarantee prevents a true split for volume-backed apps, but a hard partition can briefly double-run stateless copies. Tunable via
FOLD_HOST_TIMEOUT.Tests
drainHostreschedules a started machine onto the live host and leaves it desired-starteddrainHostunplaces a suspended machine and clears its stale snapshotsweepHostsmarks a stale host down, and a heartbeat recovers it to upVerification
gofmt -lclean ·go vet ./...clean ·go test ./...all pass ·go build -tags firecracker ./...compilesmake e2e-localpasses (no regression in deploy/scale-to-zero/wake — wake path was touched)fold hosts listflip the host todown(with a WARNhost missed heartbeatslog), then back toupafter restarting the agent🤖 Generated with Claude Code