Harden view-list caching diagnostics and coalescing.
Add cache-hit/source metadata for pin, reaction, and discovery list spans, coalesce in-flight discovery list fetches, and batch view lookups to reduce redundant reads during render bursts. Co-authored-by: Cursor <[email protected]>
This commit is contained in:
@@ -8,6 +8,7 @@ Application facade: one `PearcordPlatform` class that wires identity, database,
|
||||
**Phase 661 (v0.8.640):** Added dependency guard scripts: `test:deps` compares `require('pearcord-*')` usage vs `package.json` declarations, `test:imports` smoke-resolves imported `pearcord-*` modules, and `ci:deps` fails when undeclared imports are introduced.
|
||||
|
||||
**Phase 410 hardening (v0.8.641):** Added cached pin snapshots in `view()` (`_pinListCacheKey/_pinListCacheGen` + `_invalidatePinListCache`) and broadened reaction snapshot cache reuse beyond light polls to reduce duplicate startup list scans.
|
||||
**Phase 410 hardening (v0.8.643):** `view()` now emits cache-path span metadata for `pin.list`, `reaction.list`, and `discovery.list` (`cacheHit`, `source`), coalesces concurrent discovery listing fetches behind `_discoveryListPending`, and reports aggregate cache counters in `view.listCacheMetrics`.
|
||||
|
||||
**Phase 659 (v0.8.638):** DM scheduled messages slice — `sendMessage` parses `/schedule` and `/sendlater` in DM mode; queue APIs `createDmScheduledMessage`, `listDmScheduledMessages`, `cancelDmScheduledMessage`, `sendNowDmScheduledMessage`, plus due runner `runDueDmScheduledMessages()` and local timer flush. See [DM_SCHEDULED_MESSAGES.md](../../docs/DM_SCHEDULED_MESSAGES.md).
|
||||
|
||||
|
||||
@@ -488,10 +488,14 @@ class PearcordPlatform extends EventEmitter {
|
||||
this._reactionListCache = null
|
||||
this._reactionListCacheGen = 0
|
||||
this._reactionListPending = null
|
||||
this._reactionListMetrics = { cacheHit: 0, pendingHit: 0, miss: 0 }
|
||||
this._pinListCacheKey = ''
|
||||
this._pinListCache = null
|
||||
this._pinListCacheGen = 0
|
||||
this._pinListPending = null
|
||||
this._pinListMetrics = { cacheHit: 0, pendingHit: 0, miss: 0 }
|
||||
this._discoveryListPending = null
|
||||
this._discoveryListMetrics = { cacheHit: 0, pendingHit: 0, miss: 0 }
|
||||
this._lastReplicationCompact = null
|
||||
this._memberPageBurstTimestamps = []
|
||||
this._guildMeshBoundedByGuild = new Map()
|
||||
@@ -20068,6 +20072,26 @@ class PearcordPlatform extends EventEmitter {
|
||||
) {
|
||||
reactions = this._reactionListCache.reactions
|
||||
const cachedRows = Array.isArray(this._reactionListCache.rows) ? this._reactionListCache.rows : []
|
||||
this._reactionListMetrics.cacheHit += 1
|
||||
const listSpan = this.log.time('reaction.list', {
|
||||
spanKind: 'reaction.list',
|
||||
channelId: this.activeChannelId,
|
||||
guildId: reactionGuildId,
|
||||
light
|
||||
})
|
||||
listSpan.end({
|
||||
spanKind: 'reaction.list',
|
||||
channelId: this.activeChannelId,
|
||||
guildId: reactionGuildId,
|
||||
rowCount: cachedRows.length,
|
||||
messageCount: Object.keys(reactions).length,
|
||||
activeChannelId: this.activeChannelId,
|
||||
guildCount: (this.guilds || []).length,
|
||||
cached: true,
|
||||
cacheHit: true,
|
||||
source: 'cache',
|
||||
light
|
||||
})
|
||||
this.log.debug('reaction.list cache hit', {
|
||||
spanKind: 'reaction.list',
|
||||
channelId: this.activeChannelId,
|
||||
@@ -20083,6 +20107,7 @@ class PearcordPlatform extends EventEmitter {
|
||||
const pending = this._reactionListPending
|
||||
if (pending && pending.cacheKey === cacheKey) {
|
||||
const rowCount = Array.isArray(pending.rows) ? pending.rows.length : null
|
||||
this._reactionListMetrics.pendingHit += 1
|
||||
this.log.debug('reaction.list pending cache hit', {
|
||||
spanKind: 'reaction.list',
|
||||
channelId: this.activeChannelId,
|
||||
@@ -20097,10 +20122,32 @@ class PearcordPlatform extends EventEmitter {
|
||||
try {
|
||||
const out = await pending.promise
|
||||
reactions = out.reactions || {}
|
||||
const pendingRows = Array.isArray(out.rows) ? out.rows : []
|
||||
const listSpan = this.log.time('reaction.list', {
|
||||
spanKind: 'reaction.list',
|
||||
channelId: this.activeChannelId,
|
||||
guildId: reactionGuildId,
|
||||
light
|
||||
})
|
||||
listSpan.end({
|
||||
spanKind: 'reaction.list',
|
||||
channelId: this.activeChannelId,
|
||||
guildId: reactionGuildId,
|
||||
rowCount: pendingRows.length,
|
||||
messageCount: Object.keys(reactions).length,
|
||||
activeChannelId: this.activeChannelId,
|
||||
guildCount: (this.guilds || []).length,
|
||||
cached: true,
|
||||
cacheHit: true,
|
||||
pending: true,
|
||||
source: 'pending',
|
||||
light
|
||||
})
|
||||
} catch {
|
||||
reactions = {}
|
||||
}
|
||||
} else {
|
||||
this._reactionListMetrics.miss += 1
|
||||
const listSpan = this.log.time('reaction.list', {
|
||||
spanKind: 'reaction.list',
|
||||
channelId: this.activeChannelId,
|
||||
@@ -20127,6 +20174,8 @@ class PearcordPlatform extends EventEmitter {
|
||||
activeChannelId: this.activeChannelId,
|
||||
guildCount: (this.guilds || []).length,
|
||||
cached: false,
|
||||
cacheHit: false,
|
||||
source: 'fresh',
|
||||
light
|
||||
})
|
||||
} catch (err) {
|
||||
@@ -20163,13 +20212,15 @@ class PearcordPlatform extends EventEmitter {
|
||||
activeChannelOverwrites = await this._channelOverwrites(this.activeChannelId)
|
||||
}
|
||||
let pins = []
|
||||
let usersById =
|
||||
guild && members.length ? await this._usersById(members) : {}
|
||||
const mentionNames = new Set()
|
||||
if (user) {
|
||||
mentionNames.add(user.username)
|
||||
if (user.displayName) mentionNames.add(user.displayName)
|
||||
}
|
||||
for (const mem of members) {
|
||||
const u = await this.db.get(COLLECTIONS.USERS, { id: mem.userId })
|
||||
const u = usersById[mem.userId]
|
||||
if (u?.username) mentionNames.add(u.username)
|
||||
if (u?.displayName) mentionNames.add(u.displayName)
|
||||
if (mem.nickname) mentionNames.add(mem.nickname)
|
||||
@@ -20179,6 +20230,23 @@ class PearcordPlatform extends EventEmitter {
|
||||
const pinCacheKey = `${pinGuildId}:${this.activeChannelId || ''}:${this._pinListCacheGen || 0}`
|
||||
if (this._pinListCacheKey === pinCacheKey && Array.isArray(this._pinListCache?.pins)) {
|
||||
pins = this._pinListCache.pins
|
||||
this._pinListMetrics.cacheHit += 1
|
||||
const listSpan = this.log.time('pin.list', {
|
||||
spanKind: 'search.pins',
|
||||
channelId: this.activeChannelId,
|
||||
guildId: pinGuildId
|
||||
})
|
||||
listSpan.end({
|
||||
spanKind: 'search.pins',
|
||||
channelId: this.activeChannelId,
|
||||
guildId: pinGuildId,
|
||||
guildCount: (this.guilds || []).length,
|
||||
pinCount: pins.length,
|
||||
activeChannelId: this.activeChannelId,
|
||||
cached: true,
|
||||
cacheHit: true,
|
||||
source: 'cache'
|
||||
})
|
||||
this.log.debug('pin.list cache hit', {
|
||||
spanKind: 'search.pins',
|
||||
channelId: this.activeChannelId,
|
||||
@@ -20191,6 +20259,7 @@ class PearcordPlatform extends EventEmitter {
|
||||
} else {
|
||||
const pending = this._pinListPending
|
||||
if (pending && pending.cacheKey === pinCacheKey) {
|
||||
this._pinListMetrics.pendingHit += 1
|
||||
this.log.debug('pin.list pending cache hit', {
|
||||
spanKind: 'search.pins',
|
||||
channelId: this.activeChannelId,
|
||||
@@ -20203,10 +20272,28 @@ class PearcordPlatform extends EventEmitter {
|
||||
})
|
||||
try {
|
||||
pins = await pending.promise
|
||||
const listSpan = this.log.time('pin.list', {
|
||||
spanKind: 'search.pins',
|
||||
channelId: this.activeChannelId,
|
||||
guildId: pinGuildId
|
||||
})
|
||||
listSpan.end({
|
||||
spanKind: 'search.pins',
|
||||
channelId: this.activeChannelId,
|
||||
guildId: pinGuildId,
|
||||
guildCount: (this.guilds || []).length,
|
||||
pinCount: pins.length,
|
||||
activeChannelId: this.activeChannelId,
|
||||
cached: true,
|
||||
cacheHit: true,
|
||||
pending: true,
|
||||
source: 'pending'
|
||||
})
|
||||
} catch {
|
||||
pins = []
|
||||
}
|
||||
} else {
|
||||
this._pinListMetrics.miss += 1
|
||||
const loader = this._channelPins(this.activeChannelId, pinGuildId)
|
||||
this._pinListPending = { cacheKey: pinCacheKey, promise: loader, pins: null }
|
||||
try {
|
||||
@@ -20229,17 +20316,22 @@ class PearcordPlatform extends EventEmitter {
|
||||
if (ma?.count) mentionAlerts[ma.channelId] = ma.count
|
||||
}
|
||||
if (guild) {
|
||||
for (const ch of channels) {
|
||||
const settingsChannels = channels.filter((ch) => {
|
||||
if (
|
||||
ch.type !== 'text' &&
|
||||
ch.type !== 'thread' &&
|
||||
ch.type !== 'forum' &&
|
||||
ch.type !== 'announcement'
|
||||
) {
|
||||
continue
|
||||
return false
|
||||
}
|
||||
const s = await this.getChannelSettings(ch.id, guild.id)
|
||||
channelSettings[ch.id] = s
|
||||
return true
|
||||
})
|
||||
const settingsRows = await Promise.all(
|
||||
settingsChannels.map(async (ch) => [ch.id, await this.getChannelSettings(ch.id, guild.id)])
|
||||
)
|
||||
for (const [channelId, s] of settingsRows) {
|
||||
channelSettings[channelId] = s
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20272,8 +20364,6 @@ class PearcordPlatform extends EventEmitter {
|
||||
if (rows.length) attachmentsByMessage[m.id] = rows
|
||||
}
|
||||
}
|
||||
let usersById =
|
||||
guild && members.length ? await this._usersById(members) : {}
|
||||
if (user?.id) usersById = { ...usersById, [user.id]: user }
|
||||
if (this.mode === 'dm') {
|
||||
usersById = {
|
||||
@@ -20298,7 +20388,7 @@ class PearcordPlatform extends EventEmitter {
|
||||
const memberNameById = {}
|
||||
if (guild) {
|
||||
for (const mem of members) {
|
||||
const u = await this.db.get(COLLECTIONS.USERS, { id: mem.userId })
|
||||
const u = usersById[mem.userId]
|
||||
memberNameById[mem.userId] = mem.nickname || u?.displayName || u?.username || mem.userId.slice(0, 8)
|
||||
}
|
||||
}
|
||||
@@ -20416,6 +20506,7 @@ class PearcordPlatform extends EventEmitter {
|
||||
this._cachedPublicListings &&
|
||||
now - (this._cachedPublicListingsAt || 0) < cacheMs
|
||||
if (cacheFresh) {
|
||||
this._discoveryListMetrics.cacheHit += 1
|
||||
publicListings = this._cachedPublicListings
|
||||
if (!light) {
|
||||
const filter = this._discoveryFilter
|
||||
@@ -20435,14 +20526,29 @@ class PearcordPlatform extends EventEmitter {
|
||||
minMembers: Number(filter?.minMembers || 0),
|
||||
peerCount: this.discovery?.peers?.size ?? 0,
|
||||
activeChannelId: this.activeChannelId,
|
||||
guildCount: (this.guilds || []).length
|
||||
guildCount: (this.guilds || []).length,
|
||||
cacheHit: true
|
||||
})
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
const resolveListings = async () => {
|
||||
if (this._discoveryListPending?.promise) {
|
||||
this._discoveryListMetrics.pendingHit += 1
|
||||
return this._discoveryListPending.promise
|
||||
}
|
||||
this._discoveryListMetrics.miss += 1
|
||||
const loader = this.discovery.listPublicListings()
|
||||
this._discoveryListPending = { promise: loader }
|
||||
try {
|
||||
return await loader
|
||||
} finally {
|
||||
this._discoveryListPending = null
|
||||
}
|
||||
}
|
||||
if (!light) {
|
||||
const listSpan = this.log.time('discovery.list', { spanKind: 'discovery.list' })
|
||||
publicListings = await this.discovery.listPublicListings()
|
||||
publicListings = await resolveListings()
|
||||
const filter = this._discoveryFilter
|
||||
const filteredCount = this.discovery
|
||||
? this.discovery.filterPublicListings(publicListings, filter).length
|
||||
@@ -20459,10 +20565,11 @@ class PearcordPlatform extends EventEmitter {
|
||||
minMembers: Number(filter?.minMembers || 0),
|
||||
peerCount: this.discovery?.peers?.size ?? 0,
|
||||
activeChannelId: this.activeChannelId,
|
||||
guildCount: (this.guilds || []).length
|
||||
guildCount: (this.guilds || []).length,
|
||||
cacheHit: false
|
||||
})
|
||||
} else {
|
||||
publicListings = await this.discovery.listPublicListings()
|
||||
publicListings = await resolveListings()
|
||||
}
|
||||
this._cachedPublicListings = publicListings
|
||||
this._cachedPublicListingsAt = now
|
||||
@@ -21130,6 +21237,11 @@ class PearcordPlatform extends EventEmitter {
|
||||
publicListings,
|
||||
filteredPublicListings,
|
||||
discoveryFilter: { ...this._discoveryFilter },
|
||||
listCacheMetrics: {
|
||||
reactions: { ...this._reactionListMetrics },
|
||||
pins: { ...this._pinListMetrics },
|
||||
discovery: { ...this._discoveryListMetrics }
|
||||
},
|
||||
discoveryAllTags,
|
||||
discoveryStats,
|
||||
linkEmbedsByMessage,
|
||||
|
||||
Reference in New Issue
Block a user