Slurm: a new leader with nothing kept waits for the nodes a while
CI / test (push) Failing after 7m57s

On a cluster upgraded to the kept nodes, the first leader finds none and
wrote slurm.conf without the nodes it had not heard from yet, as before.
A node neither reported nor kept now holds the controller's files back
for slurmsvc.HoldFor (2 minutes) from the leader's first pass.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Ilker ManapandClaude Opus 5.5 committed 2026-11-11 22:37:52 +01:00
1 parent 141a1f46c5
commit 0774e901c0
2 files changed
+30 -1

No files matched your search

@@ -5,6 +5,7 @@ import (
"errors"
"strings"
"testing"
"time"
llmgwv1 "gitea.mynodes.xyz/ilker/llmgw/api/gen/llmgw/v1"
"gitea.mynodes.xyz/ilker/llmgw/internal/config"
@@ -115,3 +116,18 @@ func TestWithTheStoreUnreadTheControllerIsSentNothingThatLeavesANodeOut(t *testi
t.Fatal("with every node reported, the controller still got no files")
}
}
func TestWithNothingKeptANewLeaderWaitsForTheNodesAWhile(t *testing.T) {
r := newRig()
r.svc.SetMemory(StoreMemory(&fakeKV{m: map[string]string{}}))
r.tick()
if m := r.agents.last("node06"); m != nil {
t.Fatalf("with nothing kept, the controller was sent %v before cuda01 reported", m)
}
defer func(d time.Duration) { HoldFor = d }(HoldFor)
HoldFor = 0
r.tick()
if m := r.agents.last("node06"); !m.GetController() || strings.Contains(m.GetFiles()["slurm.conf"], "NodeName=cuda01") {
t.Fatalf("after the wait, the controller was told %v", m)
}
}
+14 -1
View File
@@ -123,8 +123,18 @@ type Service struct {
mem Memory
known Kept
loaded bool
// started is the first pass, from which a node neither heard from nor
// kept is waited for, for HoldFor.
started time.Time
}
// HoldFor is how long a new leader waits for a node it neither has heard
// from nor finds kept before it writes the controller's files without it:
// on a cluster that kept nothing yet (one upgraded to this), the nodes
// report within seconds of a new leader, and the controller keeps the
// node and its jobs meanwhile.
var HoldFor = 2 * time.Minute
// New is a Service; key gives the munge key, made once from a cluster
// secret.
func New(settings func() config.SlurmSettings, inv Inventory, agents Agents,
@@ -216,6 +226,9 @@ func (s *Service) Tick(ctx context.Context) {
s.mu.Lock()
defer s.mu.Unlock()
s.recall(ctx)
if s.started.IsZero() {
s.started = time.Now()
}
phases := s.handOver(set)
var key []byte
if set.Enabled {
@@ -232,7 +245,7 @@ func (s *Service) Tick(ctx context.Context) {
files, waiting := s.files(set)
// Not yet knowing what the last leader knew, a slurm.conf without some
// node would take it, and its jobs, from the controller: kept back.
hold := s.mem != nil && !s.loaded && len(waiting) > 0
hold := s.mem != nil && len(waiting) > 0 && (!s.loaded || time.Since(s.started) < HoldFor)
for _, node := range s.agents.ConnectedNodes() {
if hold && node == set.Controller {
continue