[management] use peer.Status.LastSeen field to detect stale peer.Status.Connected values (#7268)

This commit is contained in:
dmitri-netbird
2026-10-28 18:39:51 +01:00
committed by GitHub
parent 4ff3267542
commit dea73ff13f
20 changed files with 348 additions and 30 deletions
+27
View File
@@ -10,6 +10,7 @@ import (
"time"
log "github.com/sirupsen/logrus"
"gorm.io/gorm"
"github.com/netbirdio/netbird/management/server/util"
"github.com/netbirdio/netbird/shared/management/http/api"
@@ -101,6 +102,32 @@ type PeerStatus struct { //nolint:revive
RequiresApproval bool
}
const (
// HeartbeatInterval is how often the management instance serving a peer's sync
// stream refreshes the peer's LastSeen.
HeartbeatInterval = time.Minute
// StaleAfter is how long a connected peer may go without a LastSeen refresh before
// it reads as disconnected. It spans several heartbeats so one missed refresh does
// not disconnect a live peer.
StaleAfter = 5 * time.Minute
)
// IsConnected reports whether a peer stored with the given connected flag and LastSeen
// counts as connected. A management instance that stops without marking its peers
// disconnected leaves the flag set, so a peer whose LastSeen is older than StaleAfter
// reads as disconnected.
func IsConnected(connected bool, lastSeen time.Time) bool {
return connected && time.Since(lastSeen) < StaleAfter
}
// AfterFind applies IsConnected to every peer loaded through gorm.
func (p *Peer) AfterFind(*gorm.DB) error {
if p.Status != nil {
p.Status.Connected = IsConnected(p.Status.Connected, p.Status.LastSeen)
}
return nil
}
// Location is a geo location information of a Peer based on public connection IP
type Location struct {
ConnectionIP net.IP `gorm:"serializer:json"` // from grpc peer or reverse proxy headers depends on setup
+20
View File
@@ -4,6 +4,7 @@ import (
"fmt"
"net/netip"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -164,3 +165,22 @@ func TestPeerCapabilities(t *testing.T) {
})
}
}
func TestIsConnected(t *testing.T) {
tests := []struct {
name string
connected bool
lastSeen time.Time
want bool
}{
{name: "connected and recently seen", connected: true, lastSeen: time.Now().Add(-time.Minute), want: true},
{name: "connected but not seen for longer than StaleAfter", connected: true, lastSeen: time.Now().Add(-StaleAfter - time.Minute)},
{name: "connected but never seen", connected: true},
{name: "disconnected and recently seen", lastSeen: time.Now()},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert.Equal(t, tt.want, IsConnected(tt.connected, tt.lastSeen))
})
}
}