Skip to content

fix(bootstrap): restore periodic rounds when no backup peers are set - #1220

Open
guillaumemichel wants to merge 2 commits into
mainfrom
fix/bootstrap-periodic-rounds
Open

guillaumemichel wants to merge 2 commits into
mainfrom
fix/bootstrap-periodic-rounds

Conversation

@guillaumemichel

Copy link
Copy Markdown
Member

Problem

Since #710, bootstrap.Bootstrap only behaves as documented when backup peers are set with WithBackupPeers or SetBackupPeers. Without them:

  • Periodic rounds never run: after the first round, the supervisor goroutine waits on a channel that only the backup-peers path sends to. A node that later drops below MinPeerThreshold connections never gets another bootstrap round.
  • The supervisor goroutine leaks: it is blocked on that channel rather than on the context, so Close never releases it.
  • Bootstrap returns before the first round completes: while with backup peers it waits for that round.

#710 moved the first-round handshake (doneWithRound <- struct{}{}) inside if cfg.loadBackupBootstrapPeers != nil and dropped the unconditional close(doneWithRound). Without backup peers, nothing ever sends on or closes that channel. Before #710, every caller waited for the first round and got periodic rounds

Kubo always sets backup peers, so it isn't affected.

Fix

  • The supervisor closes firstRoundDone once the first round completes, then enters the periodic loop. It no longer waits on a handshake.
  • Bootstrap waits on firstRoundDone whether or not backup peers are set, then starts the backup-saving process when they are.
  • When rt.Bootstrap fails, Bootstrap cancels the context and returns the error, as before. The supervisor's first round ends early on the cancelled context, then the supervisor closes the channel and exits, so there is nothing left to unblock.

For callers without backup peers, two things change, both back to how they were before #710:

  • Bootstrap waits for the first round, which can take up to ConnectionTimeout.
  • Every Period, a round checks the connection count, and dials bootstrap peers only when it is below MinPeerThreshold. Callers with backup peers already get exactly this.

Callers with backup peers see no change, and the backup-peer API is unchanged.

@guillaumemichel
guillaumemichel requested a review from a team as a code owner October 15, 2026 14:31
@codecov

codecov Bot commented Oct 15, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 70.73%. Comparing base (3d6ac39) to head (46d947f).

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #1220      +/-   ##
==========================================
+ Coverage   70.54%   70.73%   +0.18%     
==========================================
  Files         270      270              
  Lines       27265    27264       -1     
==========================================
+ Hits        19234    19285      +51     
+ Misses       7984     7932      -52     
  Partials       47       47              
Files with missing lines Coverage Δ
bootstrap/bootstrap.go 81.62% <100.00%> (+27.85%) ⬆️

... and 4 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@gammazero gammazero left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good fix. Yes, looks like moving doneWithRound <- struct{}{} inside if cfg.loadBackupBootstrapPeers != nil was an error.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants