slice 8B (controller half): app-consistent backup quiesce loop (v0.36.0)

internal/quiesce: poll /backup/due -> quiesce (stop app stacks) -> POST /backup
-> poll /backup/status -> unquiesce (restart exactly those). Crash-safety:
persisted marker before stopping, guaranteed unquiesce (defer), max-quiesce
guard, startup Recover, single-flight. agentapi BackupDue/StartBackup/
BackupStatus; stacks.RunningAppStacks(); config QuiesceConfig; main wiring.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-10 10:44:52 +02:00
parent 10685b771c
commit 68fc153d9c
7 changed files with 813 additions and 0 deletions
+20
View File
@@ -29,6 +29,7 @@ type Config struct {
Assets AssetsConfig `yaml:"assets"`
System SystemConfig `yaml:"system"`
LocalAPI LocalAPIConfig `yaml:"local_api"`
Quiesce QuiesceConfig `yaml:"quiesce"`
}
// LocalAPIConfig is the in-guest controller's handle on the host agent's per-guest local API
@@ -40,6 +41,22 @@ type LocalAPIConfig struct {
Token string `yaml:"token"` // per-guest bearer; SECRET
}
// QuiesceConfig tunes the slice-8B app-consistent backup loop (doc 03 §8): poll the agent's
// /backup/due, and when due stop the app stacks around the agent vzdump for a clean-shutdown
// backup. Runs only when the local API is configured (a provisioned guest). MaxQuiesce bounds the
// app downtime — the controller unquiesces no matter what once it elapses.
type QuiesceConfig struct {
Enabled *bool `yaml:"enabled"` // nil/true → on when local API configured; false → off
PollInterval string `yaml:"poll_interval"` // /backup/due check cadence (default "5m")
StatusPoll string `yaml:"status_poll_interval"` // /backup/status poll while quiesced (default "10s")
MaxQuiesce string `yaml:"max_quiesce_duration"` // hard downtime bound (default "30m")
}
// QuiesceEnabled reports whether the quiesce loop should run (default on unless explicitly false).
func (q QuiesceConfig) QuiesceEnabled() bool {
return q.Enabled == nil || *q.Enabled
}
type SystemConfig struct {
ReservedMemoryMB int `yaml:"reserved_memory_mb"`
}
@@ -278,6 +295,9 @@ func applyDefaults(cfg *Config) {
d(&cfg.Assets.SourceURL, "https://felhom.eu")
d(&cfg.Assets.SyncSchedule, "05:00")
di(&cfg.System.ReservedMemoryMB, 384)
d(&cfg.Quiesce.PollInterval, "5m")
d(&cfg.Quiesce.StatusPoll, "10s")
d(&cfg.Quiesce.MaxQuiesce, "30m")
}
func applyEnvOverrides(cfg *Config) {