Version
1.1.0
Which installation method(s) does this occur on?
Helm / Kubernetes manifests
Describe the bug.
Describe the bug
The Token controller's periodic refresh can silently stop. On the reconcile scheduled at the refresh instant,
Sync() pushes RequeueAfter = refreshTime.Sub(now) where refreshTime = exp − Lifetime/5 — so it is ≤ 0 at
that moment. durationStore uses Less (keeps the minimum, no floor), so Pop returns ≤ 0, and controller-runtime
treats RequeueAfter ≤ 0 as "do not requeue." The reconcile still mints a token and writes the Secret, so the loop
continues only via the Owns(&Secret{}) watch follow-up. When that watch event is coalesced/dropped, nothing
re-enqueues the Token: it is never refreshed again, the JWT expires, and consumers get Protocol authentication error.
It self-recovers only on the ~10h cache resync or an operator restart, so tokens flap.
Introduced by f9d0a98 ("feat(token): ensure Token is refreshed timely", first shipped in v1.1.0), which added
durationStore.Push(key, refreshTime.Sub(now)) and switched the store from Greater to Less. v1.0.1 is unaffected.
Steps/Code to reproduce bug
- Create a
Token with refresh: true (default 15m lifetime).
- In the token-controller logs, each cycle emits two
Finished syncing Token lines — one with no result
(the mint, RequeueAfter ≤ 0) and one with result.RequeueAfter ≈ +12m (the Owns(Secret) follow-up).
- Eventually a cycle emits only the no-result reconcile (the follow-up watch event is coalesced). After that there are
no further Token reconciles until the ~10h resync; the Secret's JWT expires and stops being refreshed.
Expected behavior
A Token with refresh: true never expires. The controller should arm its own next refresh on every reconcile —
compute the requeue from the newly-minted token's exp, and never return RequeueAfter ≤ 0 (floor to a positive
minimum, or set Requeue: true) — removing the dependency on the Owns(Secret) watch.
Environment details (please complete the following information):
- Environment location: Cloud (Kubernetes)
- Install / deployment method: Helm; slurm-operator v1.1.0 (also present on current
main and v1.1.1)
Additional context
Relevant code: internal/controller/token/token_sync.go (the refreshTime.Sub(now) push),
internal/controller/token/token_controller.go (res = reconcile.Result{RequeueAfter: durationStore.Pop(req.String())},
no floor), and internal/utils/durationstore (Less, stores ≤0 verbatim, no clamp). The fix is small and local to
the token controller.
Minimum reproducible example
Relevant log output
Additional environment details
Other/Misc.
No response
Code of Conduct
Version
1.1.0
Which installation method(s) does this occur on?
Helm / Kubernetes manifests
Describe the bug.
Describe the bug
The Token controller's periodic refresh can silently stop. On the reconcile scheduled at the refresh instant,
Sync()pushesRequeueAfter = refreshTime.Sub(now)whererefreshTime = exp − Lifetime/5— so it is≤ 0atthat moment.
durationStoreusesLess(keeps the minimum, no floor), soPopreturns≤ 0, and controller-runtimetreats
RequeueAfter ≤ 0as "do not requeue." The reconcile still mints a token and writes the Secret, so the loopcontinues only via the
Owns(&Secret{})watch follow-up. When that watch event is coalesced/dropped, nothingre-enqueues the Token: it is never refreshed again, the JWT expires, and consumers get
Protocol authentication error.It self-recovers only on the ~10h cache resync or an operator restart, so tokens flap.
Introduced by
f9d0a98("feat(token): ensure Token is refreshed timely", first shipped in v1.1.0), which addeddurationStore.Push(key, refreshTime.Sub(now))and switched the store fromGreatertoLess. v1.0.1 is unaffected.Steps/Code to reproduce bug
Tokenwithrefresh: true(default 15m lifetime).Finished syncing Tokenlines — one with noresult(the mint,
RequeueAfter ≤ 0) and one withresult.RequeueAfter ≈ +12m(theOwns(Secret)follow-up).no further Token reconciles until the ~10h resync; the Secret's JWT expires and stops being refreshed.
Expected behavior
A
Tokenwithrefresh: truenever expires. The controller should arm its own next refresh on every reconcile —compute the requeue from the newly-minted token's
exp, and never returnRequeueAfter ≤ 0(floor to a positiveminimum, or set
Requeue: true) — removing the dependency on theOwns(Secret)watch.Environment details (please complete the following information):
mainandv1.1.1)Additional context
Relevant code:
internal/controller/token/token_sync.go(therefreshTime.Sub(now)push),internal/controller/token/token_controller.go(res = reconcile.Result{RequeueAfter: durationStore.Pop(req.String())},no floor), and
internal/utils/durationstore(Less, stores≤0verbatim, no clamp). The fix is small and local tothe token controller.
Minimum reproducible example
Relevant log output
Additional environment details
Other/Misc.
No response
Code of Conduct