R-85 Phase 1: the restore-test spec is built PER RUN, not frozen at daemon start

SchedulerOptions.Spec was a VALUE produced by an immediately-invoked function
at daemon start, so storageTier() and restoreTaskTimeout() were evaluated once
and reused for every run for the process lifetime. Nothing tier-varying was
expressible (the offsite tier could never be scheduled), and it was a latent
staleness bug besides: a storage-type or config change did not take effect
until restart.

- backup.SpecBuilder: func(ctx, archive) RestoreTestSpec, called once per run.
  The archive is passed because the tier MUST come from it (v0.100.0 rule) —
  config-derived is what classified a PBS archive as 'local' and killed a
  14.46 GB WAN restore at the 10-minute local bound.
- A nil spec builder SKIPS loudly instead of panicking: a wiring bug must cost a
  restore-test, never the daemon goroutine.

Red-proof observed. Full suite green (29 packages, rc=0).
This commit is contained in:
Claude Code
2026-07-26 20:47:28 +02:00
parent edde8a01ca
commit 765d8b3168
5 changed files with 204 additions and 14 deletions
+14 -3
View File
@@ -1247,8 +1247,19 @@ func buildRestoreTestScheduler(cfg config.Config, px *proxmox.Client, engine *re
Runner: engine,
Pick: runner.PickRestoreCandidate,
Store: store,
Spec: func() reconcile.RestoreTestSpec {
tier := storageTier(context.Background(), px, target)
// R-85 (1.1): the spec is built PER RUN, from the archive that was picked.
//
// This used to be an immediately-invoked function, so storageTier() and
// restoreTaskTimeout() ran ONCE at daemon start and their result was reused for every run
// forever. That froze the tier — and with it the timeout — making an offsite restore-test
// impossible to schedule, and leaving any storage-type or config change stale until the
// daemon restarted.
//
// The tier comes from the ARCHIVE (restoreTierForArchive, the v0.100.0 rule), never from
// the configured target: config-derived was what classified a PBS archive as "local" and
// killed a 14.46 GB WAN restore at the 10-minute local bound.
Spec: func(ctx context.Context, archive string) reconcile.RestoreTestSpec {
tier := restoreTierForArchive(ctx, px, archive, target)
return reconcile.RestoreTestSpec{
RestoreStorage: cfg.Backup.RestoreStorage,
ScratchMin: min,
@@ -1256,7 +1267,7 @@ func buildRestoreTestScheduler(cfg config.Config, px *proxmox.Client, engine *re
SourceTier: tier,
RestoreTaskTimeout: restoreTaskTimeout(cfg, tier),
}
}(),
},
Cadence: cadence,
Logger: logger,
})