From 31c77805ced4b9377c4a73485a2fa62d94409cbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zolt=C3=A1n=20Papp?= Date: Tue, 18 Aug 2026 12:49:45 +0200 Subject: [PATCH] Restart the relay guard settle timer on every network transition --- shared/relay/client/guard.go | 21 ++++++++++++++------- shared/relay/client/guard_test.go | 30 ++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 7 deletions(-) create mode 100644 shared/relay/client/guard_test.go diff --git a/shared/relay/client/guard.go b/shared/relay/client/guard.go index d7ea9c0b4..a62f8772d 100644 --- a/shared/relay/client/guard.go +++ b/shared/relay/client/guard.go @@ -223,17 +223,24 @@ func (g *Guard) waitForNetwork(ctx context.Context) bool { case <-settle.C: return true case <-changedCh: - continue + case <-ctx.Done(): + return false + } + } else { + select { + case <-budget.C: + return true + case <-changedCh: case <-ctx.Done(): return false } } - select { - case <-budget.C: - return true - case <-changedCh: - case <-ctx.Done(): - return false + if !settle.Stop() { + select { + case <-settle.C: + default: + } } + settle.Reset(settleWindow) } } diff --git a/shared/relay/client/guard_test.go b/shared/relay/client/guard_test.go new file mode 100644 index 000000000..d9ee0d7b2 --- /dev/null +++ b/shared/relay/client/guard_test.go @@ -0,0 +1,30 @@ +package client + +import ( + "context" + "testing" + "time" + + "github.com/stretchr/testify/assert" + + "github.com/netbirdio/netbird/client/netstate" +) + +func TestWaitForNetworkSettlesAfterOutage(t *testing.T) { + ns := netstate.New() + ns.Set(false) + g := NewGuard(nil, 0, ns) + + const outage = 2 * verdictSettleWindow + go func() { + time.Sleep(outage) + ns.Set(true) + }() + + start := time.Now() + ok := g.waitForNetwork(context.Background()) + elapsed := time.Since(start) + + assert.True(t, ok, "recovered network must let the quick reconnect proceed") + assert.GreaterOrEqual(t, elapsed, outage+verdictSettleWindow, "reconnect must wait a full settle window after the network returns") +}