mirror of
https://github.com/netbirdio/netbird.git
synced 2026-10-06 21:49:08 +02:00
[management] Enforce the peer activity throttle inside the update
The manager checked LastSeen on the peer it already held and then issued an unconditional UPDATE, so concurrent requests for one peer could each pass the check off the same stale read and write. The cutoff now travels to the store and lands in the statement's WHERE, matching how MarkPeerConnectedIfNewerSession fences its own write, and the local check stays as the query-free fast path.
This commit is contained in:
@@ -38,18 +38,23 @@ func (m *managerImpl) RecordUserLogin(ctx context.Context, accountID string, use
|
||||
}
|
||||
|
||||
// RecordPeerSeen stamps LastSeen, the column a peer activates its owner
|
||||
// through. The throttle reads the peer the caller already holds, so a peer seen
|
||||
// inside the interval costs nothing to skip.
|
||||
// through. The peer the caller already holds answers the throttle without a
|
||||
// query, so a peer seen inside the interval costs nothing to skip; the same
|
||||
// cutoff goes to the store, which enforces it inside the UPDATE so concurrent
|
||||
// requests for one peer cannot each write off their own stale read.
|
||||
func (m *managerImpl) RecordPeerSeen(ctx context.Context, accountID string, peer *peer.Peer) error {
|
||||
if peer == nil || !countsTowardActivity(peer) {
|
||||
return nil
|
||||
}
|
||||
|
||||
if peer.Status != nil && time.Since(peer.Status.LastSeen) < peerSeenInterval {
|
||||
staleBefore := time.Now().UTC().Add(-peerSeenInterval)
|
||||
if peer.Status != nil && peer.Status.LastSeen.After(staleBefore) {
|
||||
return nil
|
||||
}
|
||||
|
||||
return m.store.RefreshPeerLastSeen(ctx, accountID, peer.ID)
|
||||
_, err := m.store.RefreshPeerLastSeen(ctx, accountID, peer.ID, staleBefore)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// countsTowardActivity reports whether the peer represents a device a person
|
||||
|
||||
@@ -29,8 +29,9 @@ type loginWrite struct {
|
||||
}
|
||||
|
||||
type seenWrite struct {
|
||||
accountID string
|
||||
peerID string
|
||||
accountID string
|
||||
peerID string
|
||||
staleBefore time.Time
|
||||
}
|
||||
|
||||
func (s *recordingStore) SaveUserLastLogin(_ context.Context, accountID, userID string, lastLogin time.Time) error {
|
||||
@@ -38,9 +39,9 @@ func (s *recordingStore) SaveUserLastLogin(_ context.Context, accountID, userID
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *recordingStore) RefreshPeerLastSeen(_ context.Context, accountID, peerID string) error {
|
||||
s.seen = append(s.seen, seenWrite{accountID: accountID, peerID: peerID})
|
||||
return nil
|
||||
func (s *recordingStore) RefreshPeerLastSeen(_ context.Context, accountID, peerID string, staleBefore time.Time) (bool, error) {
|
||||
s.seen = append(s.seen, seenWrite{accountID: accountID, peerID: peerID, staleBefore: staleBefore})
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func TestRecordUserLogin(t *testing.T) {
|
||||
@@ -140,6 +141,9 @@ func TestRecordPeerSeen(t *testing.T) {
|
||||
require.Len(t, st.seen, 1, "exactly one activity write should have been recorded")
|
||||
assert.Equal(t, "account1", st.seen[0].accountID, "activity must be recorded against the service account")
|
||||
assert.Equal(t, tt.peer.ID, st.seen[0].peerID, "activity must be recorded against the calling peer")
|
||||
assert.Equal(t, time.UTC, st.seen[0].staleBefore.Location(), "cutoffs are passed in UTC")
|
||||
assert.WithinDuration(t, time.Now().UTC().Add(-peerSeenInterval), st.seen[0].staleBefore, time.Minute,
|
||||
"the store must enforce the same interval the local check applies")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user