Add mesh churn observability and reaction list light-poll cache.
Emit guild.mesh.churn spans on peer join/leave, push slot rotation, and gossip outbox flush; refresh discovery after offline recovery; cache reactions during light view polls to cut HyperDB load. Co-authored-by: Cursor <[email protected]>
This commit is contained in:
@@ -454,6 +454,30 @@ class PearcordPlatform extends EventEmitter {
|
||||
this._contactsPresenceDebounce = null
|
||||
this._lastGuildSyncIngestStart = 0
|
||||
this._guildSyncBandwidthPeerIndex = 0
|
||||
this._reactionListCacheKey = ''
|
||||
this._reactionListCache = null
|
||||
this._reactionListCacheGen = 0
|
||||
}
|
||||
|
||||
_invalidateReactionListCache () {
|
||||
this._reactionListCacheGen = (this._reactionListCacheGen || 0) + 1
|
||||
this._reactionListCacheKey = ''
|
||||
this._reactionListCache = null
|
||||
}
|
||||
|
||||
_logMeshChurn (action, extra = {}) {
|
||||
const guildId = extra.guildId || this.guild?.guild?.id
|
||||
if (!guildId) return
|
||||
this.log.info('guild.mesh.churn', {
|
||||
spanKind: 'guild.mesh.churn',
|
||||
action,
|
||||
guildId,
|
||||
meshPeerCount: this.guild?.peers?.size ?? 0,
|
||||
pushPeerSlot: this._guildSyncPushPeerSlot ?? null,
|
||||
pushHalted: this._isGuildSyncPushHalted(guildId),
|
||||
pendingGossipCount: this._guildGossipOutbox?.size ?? 0,
|
||||
...extra
|
||||
})
|
||||
}
|
||||
|
||||
_reactionTombstoneKey (key, guildId) {
|
||||
@@ -3461,12 +3485,30 @@ class PearcordPlatform extends EventEmitter {
|
||||
return { queued: true }
|
||||
}
|
||||
|
||||
async _flushGuildGossipOutbox () {
|
||||
async _flushGuildGossipOutbox (opts = {}) {
|
||||
const guildId = this.guild?.guild?.id
|
||||
const before = this._guildGossipOutbox.size
|
||||
const out = await this._guildGossipOutbox.flush()
|
||||
this._patchGuildSyncHealth({
|
||||
guildId: this.guild?.guild?.id,
|
||||
guildId,
|
||||
pendingGossipCount: this._guildGossipOutbox.size
|
||||
})
|
||||
const flushed = Number(out?.flushed) || 0
|
||||
if (guildId && flushed > 0) {
|
||||
this._logMeshChurn('gossip-outbox-flush', {
|
||||
guildId,
|
||||
flushed,
|
||||
remaining: Number(out?.remaining) || this._guildGossipOutbox.size,
|
||||
reason: opts.reason || null
|
||||
})
|
||||
} else if (guildId && before > 0 && opts.reason === 'peer-join') {
|
||||
this._logMeshChurn('gossip-outbox-flush', {
|
||||
guildId,
|
||||
flushed: 0,
|
||||
remaining: before,
|
||||
reason: 'peer-join-empty'
|
||||
})
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
@@ -4256,6 +4298,7 @@ class PearcordPlatform extends EventEmitter {
|
||||
createdAt
|
||||
})
|
||||
if (inTs > tombTs) this._reactionTombstones.delete(tombKey)
|
||||
this._invalidateReactionListCache()
|
||||
return 1
|
||||
}
|
||||
|
||||
@@ -4270,7 +4313,10 @@ class PearcordPlatform extends EventEmitter {
|
||||
changed += await this._mergeReactionGossip(r)
|
||||
}
|
||||
span.end({ changed, rows: reactions?.length || 0 })
|
||||
if (changed > 0) this.emit('reaction')
|
||||
if (changed > 0) {
|
||||
this._invalidateReactionListCache()
|
||||
this.emit('reaction')
|
||||
}
|
||||
return changed
|
||||
}
|
||||
|
||||
@@ -4689,7 +4735,7 @@ class PearcordPlatform extends EventEmitter {
|
||||
return {
|
||||
peers: this._settingsHealthChannels?.size ?? 0,
|
||||
topic: this.identity?.user?.id
|
||||
? require('pearcord-shared').settingsTopic(this.identity.user.id)
|
||||
? require('pearcord-swarm-manager').settingsMeshTopicLabel(this.identity.user.id)
|
||||
: null,
|
||||
lastGossipAt: this._settingsMeshHealthLastAt || null,
|
||||
lastRemoteDeviceId: lastRemote?.deviceId || null,
|
||||
@@ -5444,10 +5490,18 @@ class PearcordPlatform extends EventEmitter {
|
||||
action: 'offline-recovery',
|
||||
guildId
|
||||
})
|
||||
const flush = await this._flushGuildGossipOutbox().catch(() => ({ flushed: 0 }))
|
||||
this._logMeshChurn('offline-recovery-start', { guildId })
|
||||
const flush = await this._flushGuildGossipOutbox({ reason: 'offline-recovery' }).catch(
|
||||
() => ({ flushed: 0 })
|
||||
)
|
||||
this.clearGuildSyncPushHalt(guildId)
|
||||
const req = this.requestGuildSyncFromHost()
|
||||
const burst = this.requestGuildSyncBurst({ clearPushHalt: false, forcePush: true })
|
||||
await this.refreshDiscoveryListingsFromMesh().catch(() => {})
|
||||
this._logMeshChurn('offline-recovery-complete', {
|
||||
guildId,
|
||||
flushed: Number(flush?.flushed ?? flush?.count) || 0
|
||||
})
|
||||
span.end({
|
||||
guildId,
|
||||
flushed: Number(flush?.flushed ?? flush?.count) || 0,
|
||||
@@ -5970,10 +6024,18 @@ class PearcordPlatform extends EventEmitter {
|
||||
}
|
||||
await this.guild.gossipGuildSync(wireBundle)
|
||||
const peerCount = this.guild.peers?.size ?? 0
|
||||
const prevSlot = this._guildSyncPushPeerSlot
|
||||
this._guildSyncPushPeerSlot = nextRoundRobinIndex(
|
||||
Math.max(1, peerCount),
|
||||
this._guildSyncPushPeerSlot
|
||||
)
|
||||
if (peerCount > 1 && this._guildSyncPushPeerSlot !== prevSlot) {
|
||||
this._logMeshChurn('push-peer-slot', {
|
||||
guildId,
|
||||
pushPeerSlot: this._guildSyncPushPeerSlot,
|
||||
meshPeerCount: peerCount
|
||||
})
|
||||
}
|
||||
const prevHealth = this.getGuildSyncHealth(guildId)
|
||||
await this._refreshGuildSyncTailWatermark(guildId, opts.priorityChannelId || opts.channelId)
|
||||
this._patchGuildSyncHealth({
|
||||
@@ -6636,6 +6698,11 @@ class PearcordPlatform extends EventEmitter {
|
||||
const gid = this.guild?.guild?.id
|
||||
const peers = this.guild?.peers?.size ?? 0
|
||||
if (gid) {
|
||||
this._logMeshChurn('peer-leave', {
|
||||
guildId: gid,
|
||||
peerId: peerId || null,
|
||||
meshPeerCount: peers
|
||||
})
|
||||
this._patchGuildSyncHealth({
|
||||
guildId: gid,
|
||||
peers,
|
||||
@@ -6662,8 +6729,15 @@ class PearcordPlatform extends EventEmitter {
|
||||
40,
|
||||
Math.min(800, Date.now() - joinedAt)
|
||||
)
|
||||
void this._flushGuildGossipOutbox().catch(() => {})
|
||||
void this._flushGuildGossipOutbox({ reason: 'peer-join' }).catch(() => {})
|
||||
const gid = this.guild?.guild?.id
|
||||
if (gid) {
|
||||
this._logMeshChurn('peer-join', {
|
||||
guildId: gid,
|
||||
peerId: peerId || null,
|
||||
meshPeerCount: this.guild?.peers?.size ?? 0
|
||||
})
|
||||
}
|
||||
const conn = peerId ? this.guild?.peers?.get(peerId) : null
|
||||
if (gid && conn) {
|
||||
void this._getGuildReplicator(gid)
|
||||
@@ -17207,6 +17281,7 @@ class PearcordPlatform extends EventEmitter {
|
||||
})
|
||||
gossipSent = true
|
||||
}
|
||||
this._invalidateReactionListCache()
|
||||
this.emit('reaction', result)
|
||||
const reactionRows = await this.messages.listReactions()
|
||||
const reactionCount = reactionRows.filter(
|
||||
@@ -17530,31 +17605,45 @@ class PearcordPlatform extends EventEmitter {
|
||||
if (this.messages) {
|
||||
const reactionGuildId =
|
||||
this.mode === 'dm' ? DM_GUILD_ID : this.guild?.guild?.id || null
|
||||
const listSpan = this.log.time('reaction.list', {
|
||||
spanKind: 'reaction.list',
|
||||
channelId: this.activeChannelId,
|
||||
guildId: reactionGuildId
|
||||
})
|
||||
try {
|
||||
const rows = await this.messages.listReactions()
|
||||
reactions = this._groupReactions(rows)
|
||||
listSpan.end({
|
||||
const cacheKey = `${reactionGuildId || ''}:${this.activeChannelId || ''}:${this._reactionListCacheGen}`
|
||||
if (
|
||||
light &&
|
||||
this._reactionListCacheKey === cacheKey &&
|
||||
this._reactionListCache?.reactions
|
||||
) {
|
||||
reactions = this._reactionListCache.reactions
|
||||
} else {
|
||||
const listSpan = this.log.time('reaction.list', {
|
||||
spanKind: 'reaction.list',
|
||||
channelId: this.activeChannelId,
|
||||
guildId: reactionGuildId,
|
||||
rowCount: rows.length,
|
||||
messageCount: Object.keys(reactions).length,
|
||||
activeChannelId: this.activeChannelId,
|
||||
guildCount: (this.guilds || []).length
|
||||
light
|
||||
})
|
||||
} catch (err) {
|
||||
this.log.error('reaction.list error', {
|
||||
channelId: this.activeChannelId,
|
||||
guildId: reactionGuildId,
|
||||
error: err?.message || String(err)
|
||||
})
|
||||
listSpan.fail(err)
|
||||
reactions = {}
|
||||
try {
|
||||
const rows = await this.messages.listReactions()
|
||||
reactions = this._groupReactions(rows)
|
||||
this._reactionListCacheKey = cacheKey
|
||||
this._reactionListCache = { rows, reactions }
|
||||
listSpan.end({
|
||||
spanKind: 'reaction.list',
|
||||
channelId: this.activeChannelId,
|
||||
guildId: reactionGuildId,
|
||||
rowCount: rows.length,
|
||||
messageCount: Object.keys(reactions).length,
|
||||
activeChannelId: this.activeChannelId,
|
||||
guildCount: (this.guilds || []).length,
|
||||
cached: false,
|
||||
light
|
||||
})
|
||||
} catch (err) {
|
||||
this.log.error('reaction.list error', {
|
||||
channelId: this.activeChannelId,
|
||||
guildId: reactionGuildId,
|
||||
error: err?.message || String(err)
|
||||
})
|
||||
listSpan.fail(err)
|
||||
reactions = {}
|
||||
}
|
||||
}
|
||||
}
|
||||
this.guilds = await this.listGuilds()
|
||||
|
||||
Reference in New Issue
Block a user