Skip to content

Commit d8a23d8

Browse files
fix(mount): ignore canceled bootstrap shutdowns
1 parent ddf5c95 commit d8a23d8

2 files changed

Lines changed: 35 additions & 0 deletions

File tree

internal/mountsync/bootstrap_test.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -435,6 +435,34 @@ func TestBootstrapStallCycleGuardPersistsAndFailsHard(t *testing.T) {
435435
}
436436
}
437437

438+
func TestBootstrapStallCycleGuardIgnoresCanceledContext(t *testing.T) {
439+
s := newBootstrapSyncer(t, newBootstrapClient(1, 1), t.TempDir(), SyncerOptions{
440+
RootCtx: context.Background(),
441+
BootstrapStallCycles: 2,
442+
})
443+
s.state.BootstrapCursor = "resume-cursor"
444+
s.state.BootstrapStallCycles = 1
445+
446+
wrappedCanceled := fmt.Errorf("mount shutting down: %w", context.Canceled)
447+
if err := s.recordBootstrapCycle("resume-cursor", nil, wrappedCanceled); err != nil {
448+
t.Fatalf("canceled context must not trip the stall guard: %v", err)
449+
}
450+
if got := s.state.BootstrapStallCycles; got != 1 {
451+
t.Fatalf("canceled context changed stall count to %d, want 1", got)
452+
}
453+
454+
// DeadlineExceeded is a failed retry at the same checkpoint, so it still
455+
// consumes the remaining attempt and produces the typed hard stop.
456+
err := s.recordBootstrapCycle("resume-cursor", nil, context.DeadlineExceeded)
457+
var stalled *BootstrapStalledError
458+
if !errors.As(err, &stalled) {
459+
t.Fatalf("deadline exceeded must count toward the stall limit, got %v", err)
460+
}
461+
if stalled.Cycles != 2 || stalled.Limit != 2 {
462+
t.Fatalf("BootstrapStalledError = %#v, want cycles=2 limit=2", stalled)
463+
}
464+
}
465+
438466
// TestBootstrapStallCycleGuardResetsOnCheckpointAdvanceAndCompletion proves
439467
// that the counter reflects lack of traversal progress, not merely errors.
440468
func TestBootstrapStallCycleGuardResetsOnCheckpointAdvanceAndCompletion(t *testing.T) {

internal/mountsync/syncer.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4584,6 +4584,13 @@ func (s *Syncer) recordBootstrapCycle(previousCursor string, previousDirectories
45844584
s.state.BootstrapStallCycles = 0
45854585
return nil
45864586
}
4587+
// Root-context cancellation means this runner is intentionally stopping,
4588+
// not that the remote checkpoint has made a retryable failed attempt. Keep
4589+
// the persisted count intact so shutdown/restart does not consume a stall
4590+
// budget. A deadline remains a real failed attempt and continues below.
4591+
if errors.Is(cause, context.Canceled) {
4592+
return nil
4593+
}
45874594
s.state.BootstrapStallCycles++
45884595
limit := s.bootstrapStallCycles
45894596
if limit <= 0 {

0 commit comments

Comments
 (0)