[management] batch disconnect and lock free reconnect (#8373)

This commit is contained in:
Pascal Fischer
2026-10-27 16:24:46 +01:00
committed by GitHub
parent 36339993bc
commit 09f1de12e8
18 changed files with 1094 additions and 144 deletions
+45 -1
View File
@@ -106,7 +106,6 @@ func (s *SqlStore) MarkPeerConnectedIfNewerSession(ctx context.Context, accountI
"peer_status_connected": true,
"peer_status_last_seen": gorm.Expr("CURRENT_TIMESTAMP"),
"peer_status_session_started_at": newSessionStartedAt,
"peer_status_login_expired": false,
})
if result.Error != nil {
return false, status.Errorf(status.Internal, "mark peer connected: %v", result.Error)
@@ -142,6 +141,51 @@ func (s *SqlStore) MarkPeerDisconnectedIfSameSession(ctx context.Context, accoun
return result.RowsAffected > 0, nil
}
// markPeersDisconnectedChunkSize bounds the sessions per statement so the
// bound parameter count stays below the database limits.
const markPeersDisconnectedChunkSize = 1000
// MarkPeersDisconnectedIfSameSession is the batched form of
// MarkPeerDisconnectedIfSameSession: one UPDATE per chunk of sessions, each
// peer guarded by its own (account, peer, session) tuple. A failed chunk does
// not stop the others, only a done ctx does; the count then covers the chunks
// that succeeded and the error joins the failures.
func (s *SqlStore) MarkPeersDisconnectedIfSameSession(ctx context.Context, sessions []types.PeerSession) (int64, error) {
var total int64
var errs []error
for start := 0; start < len(sessions); start += markPeersDisconnectedChunkSize {
if err := ctx.Err(); err != nil {
errs = append(errs, status.Errorf(status.Internal, "mark peers disconnected: %v", err))
break
}
end := min(start+markPeersDisconnectedChunkSize, len(sessions))
tuples := make([][]any, 0, end-start)
for _, session := range sessions[start:end] {
if session.SessionStartedAt == 0 {
continue
}
tuples = append(tuples, []any{session.AccountID, session.PeerID, session.SessionStartedAt})
}
if len(tuples) == 0 {
continue
}
result := s.db.WithContext(ctx).
Model(&nbpeer.Peer{}).
Where("(account_id, id, peer_status_session_started_at) IN ?", tuples).
Updates(map[string]any{
"peer_status_connected": false,
"peer_status_last_seen": gorm.Expr("CURRENT_TIMESTAMP"),
"peer_status_session_started_at": int64(0),
})
if result.Error != nil {
errs = append(errs, status.Errorf(status.Internal, "mark peers disconnected: %v", result.Error))
continue
}
total += result.RowsAffected
}
return total, errors.Join(errs...)
}
// ApproveAccountPeers marks all peers that currently require approval in the given account as approved.
func (s *SqlStore) ApproveAccountPeers(ctx context.Context, accountID string) (int, error) {
result := s.db.Model(&nbpeer.Peer{}).