From 09eb31d1fea05f94c41c4d5b295598b5bfeae327 Mon Sep 17 00:00:00 2001 From: Mathias Date: Wed, 10 Jun 2026 21:59:12 +0200 Subject: [PATCH] fix(scheduler): derive rotation offset from wall-clock, not a reset-on-restart counter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The lead-user rotation used an in-memory pass counter reset to 0 on every pod restart, so the first-listed user always re-took the lead after a restart — a deploy-heavy session re-starved the last user (the pilot stalled at 2 summaries because each deploy reset his every-other-pass lead before the 2h tick fired). Derive the offset from wall-clock (floor(now/interval)) so it advances with real time and is identical across restarts: rotation stays fair however often the pod bounces. Co-Authored-By: Claude Opus 4.8 (1M context) --- cmd/tapir/scheduler.go | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/cmd/tapir/scheduler.go b/cmd/tapir/scheduler.go index 41af918..037cc72 100644 --- a/cmd/tapir/scheduler.go +++ b/cmd/tapir/scheduler.go @@ -143,8 +143,18 @@ func runScheduler( return // disabled } - pass := 0 - runDiscoveryPass(ctx, pass, lister, runUser, log) + // Derive the rotation offset from wall-clock, NOT an in-memory counter. A + // counter reset to 0 on every pod restart always hands the lead to the + // first-listed user — so frequent deploys re-starve whoever is last (exactly + // what happened to the first pilot user during a deploy-heavy session). A + // time-based offset advances with real time and is identical across restarts, + // so the lead rotates fairly regardless of how often the pod bounces. + runPass := func() { + pass := int(time.Now().Unix() / int64(interval/time.Second)) + runDiscoveryPass(ctx, pass, lister, runUser, log) + } + + runPass() ticker := time.NewTicker(interval) defer ticker.Stop() @@ -153,8 +163,7 @@ func runScheduler( case <-ctx.Done(): return case <-ticker.C: - pass++ - runDiscoveryPass(ctx, pass, lister, runUser, log) + runPass() } } }