feat(phase967): guild mesh churn stats extract + peer join/leave keys (v0.8.934)
Non-breaking refactor — Phase 967 of the Guild Mesh Production Hardening Track. New module: - guild-mesh-churn-stats-build.js: centralises all churn event payload construction. Exports key registries (meshChurnLogBaseFieldKeys, meshChurnPeerJoinLeaveFieldKeys, meshChurnStaleEvictFieldKeys, meshChurnPushPeerSlotFieldKeys, meshChurnGossipFlushFieldKeys), corresponding listers, and five snapshot builders (buildMeshChurnPeerJoinSnapshot, buildMeshChurnPeerLeaveSnapshot, buildMeshChurnStaleEvictSnapshot, buildMeshChurnPushPeerSlotSnapshot, buildMeshChurnGossipFlushSnapshot). Call-site wiring (zero behavior change): - platform-guild-wire-mixin.js: peer-join and peer-leave logs delegate to builders - platform-guild-mesh-peer-mixin.js: stale-peer-evict log delegates to builder - platform-guild-gossip-outbox-mixin.js: gossip-outbox-flush logs delegate to builder - platform-guild-sync-export-mixin.js: push-peer-slot log delegates to builder All public APIs, event payloads, and observable behavior are identical to before. Co-authored-by: Cursor <[email protected]>
This commit is contained in:
@@ -178,6 +178,12 @@ Application facade: one `PearcordPlatform` class that wires identity, database,
|
||||
|
||||
**Phase 881 (v0.8.848):** Split `gossip-rpc-pull.js` into peer/session/validators/orchestrators/view-snapshot modules; barrel export unchanged. Bundle: `npm run test:ci-phase881`.
|
||||
|
||||
**Phase 967 (v0.8.934):** Guild mesh churn stats extract + peer join/leave keys (non-breaking). Bundle: `npm run test:ci-phase967`.
|
||||
|
||||
| Module | Role |
|
||||
|--------|------|
|
||||
| `guild-mesh-churn-stats-build.js` | Churn event field key registries and payload builders for peer-join, peer-leave, stale-evict, push-peer-slot, and gossip-flush events |
|
||||
|
||||
**Phase 966 (v0.8.933):** Guild mesh offline recovery stats extract + recovery keys (non-breaking). Bundle: `npm run test:ci-phase966`.
|
||||
|
||||
| Module | Role |
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
'use strict'
|
||||
|
||||
const meshChurnLogBaseFieldKeys = ['action', 'guildId', 'meshPeerCount', 'pushPeerSlot', 'pushHalted', 'pendingGossipCount']
|
||||
const meshChurnPeerJoinLeaveFieldKeys = ['guildId', 'peerId', 'meshPeerCount']
|
||||
const meshChurnStaleEvictFieldKeys = ['guildId', 'evicted', 'peerRetryAttempt', 'lastPeerSeenAt', 'meshPeerCount']
|
||||
const meshChurnPushPeerSlotFieldKeys = ['guildId', 'pushPeerSlot', 'meshPeerCount']
|
||||
const meshChurnGossipFlushFieldKeys = ['guildId', 'flushed', 'remaining', 'reason']
|
||||
|
||||
function listMeshChurnLogBaseFieldKeys () {
|
||||
return meshChurnLogBaseFieldKeys.slice()
|
||||
}
|
||||
|
||||
function listMeshChurnPeerJoinLeaveFieldKeys () {
|
||||
return meshChurnPeerJoinLeaveFieldKeys.slice()
|
||||
}
|
||||
|
||||
function listMeshChurnStaleEvictFieldKeys () {
|
||||
return meshChurnStaleEvictFieldKeys.slice()
|
||||
}
|
||||
|
||||
function listMeshChurnPushPeerSlotFieldKeys () {
|
||||
return meshChurnPushPeerSlotFieldKeys.slice()
|
||||
}
|
||||
|
||||
function listMeshChurnGossipFlushFieldKeys () {
|
||||
return meshChurnGossipFlushFieldKeys.slice()
|
||||
}
|
||||
|
||||
function buildMeshChurnPeerJoinSnapshot (inputs = {}) {
|
||||
const { guildId, peerId, meshPeerCount } = inputs
|
||||
return {
|
||||
guildId: guildId ?? null,
|
||||
peerId: peerId ?? null,
|
||||
meshPeerCount: meshPeerCount ?? 0
|
||||
}
|
||||
}
|
||||
|
||||
function buildMeshChurnPeerLeaveSnapshot (inputs = {}) {
|
||||
const { guildId, peerId, meshPeerCount } = inputs
|
||||
return {
|
||||
guildId: guildId ?? null,
|
||||
peerId: peerId ?? null,
|
||||
meshPeerCount: meshPeerCount ?? 0
|
||||
}
|
||||
}
|
||||
|
||||
function buildMeshChurnStaleEvictSnapshot (inputs = {}) {
|
||||
const { guildId, evicted, peerRetryAttempt, lastPeerSeenAt, meshPeerCount } = inputs
|
||||
return {
|
||||
guildId: guildId ?? null,
|
||||
evicted: Number(evicted) || 0,
|
||||
peerRetryAttempt: Number(peerRetryAttempt) || 0,
|
||||
lastPeerSeenAt: lastPeerSeenAt ?? null,
|
||||
meshPeerCount: meshPeerCount ?? 0
|
||||
}
|
||||
}
|
||||
|
||||
function buildMeshChurnPushPeerSlotSnapshot (inputs = {}) {
|
||||
const { guildId, pushPeerSlot, meshPeerCount } = inputs
|
||||
return {
|
||||
guildId: guildId ?? null,
|
||||
pushPeerSlot: pushPeerSlot ?? null,
|
||||
meshPeerCount: meshPeerCount ?? 0
|
||||
}
|
||||
}
|
||||
|
||||
function buildMeshChurnGossipFlushSnapshot (inputs = {}) {
|
||||
const { guildId, flushed, remaining, reason } = inputs
|
||||
return {
|
||||
guildId: guildId ?? null,
|
||||
flushed: Number(flushed) || 0,
|
||||
remaining: Number(remaining) || 0,
|
||||
reason: reason ?? null
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
meshChurnLogBaseFieldKeys,
|
||||
meshChurnPeerJoinLeaveFieldKeys,
|
||||
meshChurnStaleEvictFieldKeys,
|
||||
meshChurnPushPeerSlotFieldKeys,
|
||||
meshChurnGossipFlushFieldKeys,
|
||||
listMeshChurnLogBaseFieldKeys,
|
||||
listMeshChurnPeerJoinLeaveFieldKeys,
|
||||
listMeshChurnStaleEvictFieldKeys,
|
||||
listMeshChurnPushPeerSlotFieldKeys,
|
||||
listMeshChurnGossipFlushFieldKeys,
|
||||
buildMeshChurnPeerJoinSnapshot,
|
||||
buildMeshChurnPeerLeaveSnapshot,
|
||||
buildMeshChurnStaleEvictSnapshot,
|
||||
buildMeshChurnPushPeerSlotSnapshot,
|
||||
buildMeshChurnGossipFlushSnapshot
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
'use strict'
|
||||
|
||||
const { buildMeshChurnGossipFlushSnapshot } = require('../../../guild-mesh-churn-stats-build')
|
||||
const { ensureGuildWireChannels } = require('pearcord-guild/mesh')
|
||||
const { wireReady } = require('pearcord-drive/mux-wire')
|
||||
const swarmScope = require('../../../platform-swarm-manager-imports')
|
||||
@@ -66,19 +67,19 @@ const platformGuildGossipOutboxMixin = {
|
||||
reason: opts.reason || null,
|
||||
laneCounts
|
||||
})
|
||||
this._logMeshChurn('gossip-outbox-flush', {
|
||||
this._logMeshChurn('gossip-outbox-flush', buildMeshChurnGossipFlushSnapshot({
|
||||
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', {
|
||||
this._logMeshChurn('gossip-outbox-flush', buildMeshChurnGossipFlushSnapshot({
|
||||
guildId,
|
||||
flushed: 0,
|
||||
remaining: before,
|
||||
reason: 'peer-join-empty'
|
||||
})
|
||||
}))
|
||||
}
|
||||
return out
|
||||
},
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
'use strict'
|
||||
|
||||
const { buildMeshChurnPushPeerSlotSnapshot } = require('../../../guild-mesh-churn-stats-build')
|
||||
|
||||
const {
|
||||
fs, path, b4a, EventEmitter,
|
||||
swarmScope, dmScope, appEventsScope, automationScope,
|
||||
@@ -1495,11 +1497,11 @@ async _pushGuildSyncToMesh (opts = {}) {
|
||||
this._guildSyncPushPeerSlot
|
||||
)
|
||||
if (peerCount > 1 && this._guildSyncPushPeerSlot !== prevSlot) {
|
||||
this._logMeshChurn('push-peer-slot', {
|
||||
this._logMeshChurn('push-peer-slot', buildMeshChurnPushPeerSlotSnapshot({
|
||||
guildId,
|
||||
pushPeerSlot: this._guildSyncPushPeerSlot,
|
||||
meshPeerCount: peerCount
|
||||
})
|
||||
}))
|
||||
}
|
||||
const prevHealth = this.getGuildSyncHealth(guildId)
|
||||
await this._refreshGuildSyncTailWatermark(guildId, opts.priorityChannelId || opts.channelId)
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
'use strict'
|
||||
|
||||
const {
|
||||
buildMeshChurnPeerLeaveSnapshot,
|
||||
buildMeshChurnPeerJoinSnapshot
|
||||
} = require('../../../guild-mesh-churn-stats-build')
|
||||
|
||||
const {
|
||||
fs, path, b4a, EventEmitter,
|
||||
swarmScope, dmScope, appEventsScope, automationScope,
|
||||
@@ -431,11 +436,11 @@ _wireGuild (guildInstance) {
|
||||
this._forgetGuildMeshPeerSeen(gid, peerId)
|
||||
}
|
||||
if (gid) {
|
||||
this._logMeshChurn('peer-leave', {
|
||||
this._logMeshChurn('peer-leave', buildMeshChurnPeerLeaveSnapshot({
|
||||
guildId: gid,
|
||||
peerId: peerId || null,
|
||||
meshPeerCount: peers
|
||||
})
|
||||
}))
|
||||
this._patchGuildSyncHealth({
|
||||
guildId: gid,
|
||||
peers,
|
||||
@@ -488,11 +493,11 @@ _wireGuild (guildInstance) {
|
||||
peerRetryAttempt: this._getGuildMeshPeerRetryAttempt(gid)
|
||||
})
|
||||
this._maybeEvictStaleGuildMeshPeers(gid, 'peer-join-sweep')
|
||||
this._logMeshChurn('peer-join', {
|
||||
this._logMeshChurn('peer-join', buildMeshChurnPeerJoinSnapshot({
|
||||
guildId: gid,
|
||||
peerId: peerId || null,
|
||||
meshPeerCount: this.guild?.peers?.size ?? 0
|
||||
})
|
||||
}))
|
||||
if (peerId) this._scheduleMemberEnsureFromMeshPeer(peerId, gid)
|
||||
const meshPeerCount = this.guild?.peers?.size ?? 0
|
||||
if (hadZeroPeer && meshPeerCount > 0) {
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
'use strict'
|
||||
|
||||
const { buildMeshChurnStaleEvictSnapshot } = require('../../../guild-mesh-churn-stats-build')
|
||||
|
||||
const localScope = require('../../../platform-index-local-imports')
|
||||
const swarmScope = require('../../../platform-swarm-manager-imports')
|
||||
|
||||
@@ -161,13 +163,13 @@ const platformGuildMeshPeerMixin = {
|
||||
stalePeersEvictedLast: out.evicted,
|
||||
lastStalePeerEvictAt: now
|
||||
})
|
||||
this._logMeshChurn('stale-peer-evict', {
|
||||
this._logMeshChurn('stale-peer-evict', buildMeshChurnStaleEvictSnapshot({
|
||||
guildId: gid,
|
||||
evicted: out.evicted,
|
||||
peerRetryAttempt,
|
||||
lastPeerSeenAt: maxSeen || out.lastPeerSeenAt,
|
||||
meshPeerCount: peers
|
||||
})
|
||||
}))
|
||||
if (peers === 0) this._scheduleGuildMeshPeerRetry(gid)
|
||||
}
|
||||
return out
|
||||
|
||||
Reference in New Issue
Block a user