controller v0.68.1: boot-id recreate ALL deployed drive-backed apps (state-independent)
E1 caught it: filtering on State!=stopped missed apps docker hadn't auto-restarted yet at the one-shot instant (5 apps exited after host reboot). Now recreates every deployed present drive-backed app regardless of state (deployed=should run). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -10,7 +10,6 @@ import (
|
||||
|
||||
"gitea.dooplex.hu/admin/felhom-controller/internal/agentapi"
|
||||
"gitea.dooplex.hu/admin/felhom-controller/internal/settings"
|
||||
"gitea.dooplex.hu/admin/felhom-controller/internal/stacks"
|
||||
)
|
||||
|
||||
// Intermediary-mount model (controller side). Post-migration a drive is visible in the guest ONLY at its
|
||||
@@ -40,21 +39,16 @@ func agentWhere(registeredPath string) string {
|
||||
return "/mnt/" + name
|
||||
}
|
||||
|
||||
// stackStartedRecently heuristically reports whether the stack's containers started within ~5 minutes
|
||||
// (i.e. a fresh guest boot, not a long-running app across a controller-only restart) — read from docker's
|
||||
// human "Up X …" status string. Used to limit the startup boot-stale recreate to the guest-reboot case.
|
||||
// shouldRecreateOnBoot is the PURE decision for the boot-id recreate: on a fresh guest boot, which
|
||||
// deployed drive-backed app to recreate onto its (re-propagated) drive. Recreate every app whose drive
|
||||
// is present (BoundUnderParent) AND that docker BROUGHT BACK on this boot (State not stopped/not_deployed
|
||||
// — i.e. its containers exist). A cleanly user-stopped app (compose down → no containers → Stopped) is
|
||||
// respected; a gate-stopped app is the gate's job (StoppedStacks). Deterministic — depends only on
|
||||
// deployed + drive-present + state, NOT a fragile container-uptime sample (the old `stackStartedRecently`
|
||||
// missed an app that was healthy-but-stale or stopped at the sample instant).
|
||||
func shouldRecreateOnBoot(deployed bool, hdd string, state stacks.ContainerState, presentStable map[string]bool) bool {
|
||||
if !deployed || hdd == "" || !strings.HasPrefix(hdd, StableParentDir+"/") || !presentStable[hdd] {
|
||||
return false
|
||||
}
|
||||
return state != stacks.StateStopped && state != stacks.StateNotDeployed
|
||||
// shouldRecreateOnBoot is the PURE decision for the boot-id recreate: on a fresh guest boot, recreate
|
||||
// EVERY deployed drive-backed app whose drive is present (BoundUnderParent) onto its (re-propagated)
|
||||
// drive. It is DETERMINISTIC — it depends ONLY on `app.yaml says should run` (deployed) + drive-present,
|
||||
// NOT on the app's current container state. The current state must NOT be a filter: a momentarily-stopped
|
||||
// app on a fresh reboot (docker hasn't auto-restarted it yet) would otherwise be MISSED — the exact bug
|
||||
// the boot-id path replaces (the old container-uptime sample, and a State!=stopped filter, both miss it).
|
||||
// (Tradeoff: a UI-stopped drive-backed app is brought back on a guest reboot — `deployed` is the only
|
||||
// "should run" signal app.yaml carries; the gate manages drive-backed app lifecycle otherwise.)
|
||||
func shouldRecreateOnBoot(deployed bool, hdd string, presentStable map[string]bool) bool {
|
||||
return deployed && hdd != "" && strings.HasPrefix(hdd, StableParentDir+"/") && presentStable[hdd]
|
||||
}
|
||||
|
||||
// defaultPromotionTarget decides M1 (never leave zero default). If the path being decommissioned is NOT
|
||||
@@ -285,7 +279,7 @@ func (s *Server) processGuestBootChange() {
|
||||
if cfg == nil {
|
||||
continue
|
||||
}
|
||||
if !shouldRecreateOnBoot(cfg.Deployed, cfg.Env["HDD_PATH"], st.State, presentStable) {
|
||||
if !shouldRecreateOnBoot(cfg.Deployed, cfg.Env["HDD_PATH"], presentStable) {
|
||||
continue
|
||||
}
|
||||
s.logger.Printf("[INFO] [gate] boot %s: recreating drive-backed app %s (state=%s) onto %s", resp.GuestBootID, st.Name, st.State, cfg.Env["HDD_PATH"])
|
||||
|
||||
Reference in New Issue
Block a user