v0.168.0: customer-configurable backup window (Mentési időablak)

ONE setting (window start W) drives every nightly leg at fixed, never-stored
offsets: DB dump at W, tier-2 at W+60m, off-box at W+105m (wrap-safe). Precedence
settings > controller.yaml db_dump_schedule > 02:30.

- scheduler.UpdateDaily: retime a daily job at runtime (no restart) via a per-job
  buffered resched chan + a select case in runDailyJob.
- new pure package internal/backupwindow (LegTimes/GateWindow/EffectiveWindow).
- quiesce disk-tier window gate: scheduled cycles run only inside [W+2h,W+6h) with a
  safety valve (age>cadence+24h runs regardless); manual TriggerNow never gated.
  Backend.Due now also returns the backup age (from the agent's own /backup/due).
- backup page: Mentési időablak card (time input + derived leg/gate rows); POST
  /backups/window validates -> saves -> UpdateDaily x3 -> flash.

Tests: 5 groups, all red-proofed. Agent/cadence//backup/due untouched.
This commit is contained in:
2026-07-24 20:55:44 +02:00
parent e33c1aeabc
commit 82c67e32e1
19 changed files with 831 additions and 31 deletions
+4 -2
View File
@@ -111,9 +111,9 @@ type Server struct {
// Same S-5 law as sambaAddrFn: live-computed per render/dump, stored nowhere.
guestGatewayFn func() string
guestNetFn func() stacks.GuestNetSnapshot
netAgentFn func() (netAgent, error)
netAgentFn func() (netAgent, error)
// fabUpload is the chunked browser .fab upload single-flight slot (v0.128.0).
fabUpload uploadState
fabUpload uploadState
netProbeFn func(ctx context.Context, dir string) probeOutcome
netListFn func(ctx context.Context) ([]agentapi.NetworkMountStatus, error)
// agentLogsFn is the Debug-page agent-tab seam (v0.116.0). nil → the shared
@@ -383,6 +383,8 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
s.stacksHandler(w, r)
case path == "/backups":
s.backupsHandler(w, r)
case path == "/backups/window" && r.Method == http.MethodPost:
s.backupWindowSaveHandler(w, r)
// v0.124.0 IA split: the backups page's four sub-pages (old /backups deep links keep working —
// /backups itself is the Áttekintés page).
case path == "/backups/remote":