Skip to content

Commit 2e28000

Browse files
committed
perf fixes, back out peer discovery
1 parent f071c33 commit 2e28000

14 files changed

Lines changed: 1555 additions & 77 deletions

FOLLOWUP.md

Lines changed: 273 additions & 0 deletions
Large diffs are not rendered by default.

connect/resident.go

Lines changed: 26 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,17 @@ type ExchangeSettings struct {
177177

178178
ExchangeResidentTtl time.Duration
179179

180+
// 2026-07-15: network peers DISABLED pending a pubsub throughput
181+
// redesign. The per-resident listener model (one dedicated pubsub
182+
// connection + a poll per connected top-level client) times churn-driven
183+
// publish fanout structurally exceeds cluster pubsub capacity at fleet
184+
// scale: stalled consumers stop reading their sockets for up to the 60s
185+
// channel-send timeout, server-side output buffers accumulate across tens
186+
// of thousands of subscriber connections, and the shard-channel owner
187+
// nodes are pushed to maxmemory (2026-07-15 outage). Gates registration
188+
// (announce), heartbeat refresh, teardown publish, and the listener.
189+
EnableNetworkPeers bool
190+
180191
ExchangeResidentWaitTimeout time.Duration
181192
ExchangeResidentPollTimeout time.Duration
182193

@@ -242,6 +253,7 @@ func DefaultExchangeSettingsWithBufferSize(bufferSize int) *ExchangeSettings {
242253
ExchangeWriteHeaderTimeout: exchangeResidentWaitTimeout,
243254
ExchangeReconnectAfterErrorTimeout: 1 * time.Second,
244255
ExchangeResidentTtl: 300 * time.Second,
256+
EnableNetworkPeers: false,
245257

246258
ExchangeResidentWaitTimeout: exchangeResidentWaitTimeout,
247259
ExchangeResidentPollTimeout: 15 * time.Second,
@@ -420,25 +432,11 @@ func (self *Exchange) NominateLocalResident(
420432
instanceId,
421433
residentId,
422434
)
423-
if resident.peerNetworkId != nil {
424-
if resident.peerCategory == model.NetworkPeerCategoryProxy {
425-
// proxy clients are counted but not visible peers
426-
model.AddNetworkProxyPeer(
427-
self.ctx,
428-
*resident.peerNetworkId,
429-
clientId,
430-
self.settings.ExchangeResidentTtl,
431-
)
432-
} else {
433-
model.AddNetworkPeer(
434-
self.ctx,
435-
*resident.peerNetworkId,
436-
resident.peerProfile,
437-
residentId,
438-
self.settings.ExchangeResidentTtl,
439-
)
440-
}
441-
}
435+
// note: initial peer registration happens in ConnectionAnnounce.run once
436+
// the connection survives the announce window (2026-07-15: registration
437+
// on the nomination hot path melted pubsub under connection churn and
438+
// hung nominations against memory-full redis nodes). The heartbeat below
439+
// maintains and re-adds the registration for the resident's lifetime.
442440
go server.HandleError(func() {
443441
defer func() {
444442
cleanupCtx := context.Background()
@@ -447,7 +445,10 @@ func (self *Exchange) NominateLocalResident(
447445
clientId,
448446
resident.residentId,
449447
)
450-
if resident.peerNetworkId != nil {
448+
// RemoveNetworkPeer no-ops (no publish) when this resident never
449+
// registered, so churny residents that died before announcing
450+
// emit nothing here
451+
if self.settings.EnableNetworkPeers && resident.peerNetworkId != nil {
451452
if resident.peerCategory == model.NetworkPeerCategoryProxy {
452453
model.RemoveNetworkProxyPeer(
453454
cleanupCtx,
@@ -531,10 +532,12 @@ func (self *Exchange) NominateLocalResident(
531532
// `ForwardIdleTimeout`), and without a refresh the registration
532533
// expires after `ExchangeResidentTtl` and other residents prune
533534
// it to a disconnect marker, bounding disconnect detection.
534-
if resident.peerNetworkId != nil && 0 < resident.TransportCount() {
535+
if self.settings.EnableNetworkPeers && resident.peerNetworkId != nil && 0 < resident.TransportCount() {
535536
server.HandleError(func() {
536537
if resident.peerCategory == model.NetworkPeerCategoryProxy {
537-
// AddNetworkProxyPeer doubles as the heartbeat
538+
// AddNetworkProxyPeer doubles as the heartbeat, and is
539+
// also the initial proxy registration (proxy clients
540+
// do not pass through ConnectionAnnounce)
538541
model.AddNetworkProxyPeer(self.ctx, *resident.peerNetworkId, clientId, self.settings.ExchangeResidentTtl)
539542
return
540543
}
@@ -2110,7 +2113,7 @@ func (self *Resident) Run() {
21102113
// The listener sends the complete list on subscribe (reset) and diffs
21112114
// after. Proxy clients are counted but not subscribed — a hosted device
21122115
// does not consume the peer list.
2113-
if self.peerNetworkId != nil && self.peerCategory == model.NetworkPeerCategoryClient {
2116+
if self.exchange.settings.EnableNetworkPeers && self.peerNetworkId != nil && self.peerCategory == model.NetworkPeerCategoryClient {
21142117
networkPeerListener := model.NewNetworkPeerListener(
21152118
self.ctx,
21162119
*self.peerNetworkId,

connect/transport_announce.go

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,14 @@ import (
1717

1818
func DefaultConnectionAnnounceSettings() *ConnectionAnnounceSettings {
1919
return &ConnectionAnnounceSettings{
20-
SyncConnectionTimeout: model.ReliabilityBlockDuration / 2,
21-
LocationRetryTimeout: 5 * time.Minute,
20+
SyncConnectionTimeout: model.ReliabilityBlockDuration / 2,
21+
LocationRetryTimeout: 5 * time.Minute,
22+
// matches ExchangeResidentTtl: the resident heartbeat refreshes the
23+
// registration on the same ttl
24+
PeerRegisterTtl: 300 * time.Second,
25+
// 2026-07-15: network peers disabled pending pubsub throughput
26+
// redesign (see FOLLOWUP.md "network peers pubsub")
27+
EnableNetworkPeers: false,
2228
MaxLatencyCount: 16,
2329
MinTestTimeout: 12 * time.Hour,
2430
MaxTestTimeout: 24 * time.Hour,
@@ -36,9 +42,14 @@ func DefaultConnectionAnnounceSettings() *ConnectionAnnounceSettings {
3642
type ConnectionAnnounceSettings struct {
3743
SyncConnectionTimeout time.Duration
3844
LocationRetryTimeout time.Duration
39-
MaxLatencyCount int
40-
MinTestTimeout time.Duration
41-
MaxTestTimeout time.Duration
45+
// ttl for the network peer registration made at announce
46+
PeerRegisterTtl time.Duration
47+
// mirrors ExchangeSettings.EnableNetworkPeers (2026-07-15: disabled
48+
// pending pubsub throughput redesign)
49+
EnableNetworkPeers bool
50+
MaxLatencyCount int
51+
MinTestTimeout time.Duration
52+
MaxTestTimeout time.Duration
4253

4354
LatencySampleWindowCount int
4455
SpeedSampleWindowCount int
@@ -293,6 +304,31 @@ func (self *ConnectionAnnounce) run() {
293304
self.setSpeedWithLock()
294305
}()
295306

307+
// register this client in the network peer registry, now that the
308+
// connection has survived the announce window. 2026-07-15 outage:
309+
// registration used to run on the resident nomination hot path, where
310+
// connection churn turned per-nomination publishes into a pubsub storm
311+
// (subscriber output buffers pushed redis nodes to maxmemory) and the
312+
// registry write then hung new connections against those full nodes.
313+
// Announce-time registration means churny connections that die before
314+
// announcing never publish a peer event at all. A failure here fails the
315+
// announce and tears down the connection (announce's contract) — the
316+
// panic propagates to run's HandleError cancel. Proxy clients do not pass
317+
// through announce and register via the resident heartbeat alone.
318+
// EnableNetworkPeers: see ExchangeSettings — network peers are disabled
319+
// 2026-07-15 pending a pubsub throughput redesign.
320+
if self.settings.EnableNetworkPeers {
321+
peerNetworkId, topLevel, peerCategory, peerProfile, peersEnabled := model.GetNetworkPeerProfile(self.ctx, self.clientId)
322+
if peersEnabled && topLevel && peerCategory != model.NetworkPeerCategoryProxy && peerProfile != nil {
323+
// ttl 0: read-only lookup — extending the resident record's expiry
324+
// is the resident keepalive's job, not the announce's
325+
if resident := model.GetResidentForClient(self.ctx, self.clientId, 0); resident != nil {
326+
model.AddNetworkPeer(self.ctx, peerNetworkId, peerProfile, resident.ResidentId, self.settings.PeerRegisterTtl)
327+
}
328+
// no resident nominated yet: the resident heartbeat registers it
329+
}
330+
}
331+
296332
// continuously measure the passive speed of the connection.
297333
// active traffic proves the connection speed without a synthetic test.
298334
go server.HandleError(func() {

0 commit comments

Comments
 (0)