mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-27 07:52:24 +00:00
fix(login-perf): kill relay REQ storms and feedback loops
Real-environment console logs revealed nip-07 login pegging the CPU and starving encrypted-list decryption via relay REQ storms (~1000 REQ/s): - moderationService.rebuildTrustedContacts emitted "contacts" unconditionally, forming an emit->fetch->emit loop (~1600 kind-3 REQ/s). Now emits only on actual change. Regression test added. - Per-video live report (kind 1984) and view-count (kind 30079) subscriptions fan out O(videos x relays) and re-fire on every flaky-relay reconnect. Circuit-broken behind flags until batched (see refactor plan). - onVideosShouldRefresh now coalesces forced reloads (2s leading-edge throttle) so list-change signals can't drive a reload loop. - nip-07 queue reserves one foreground slot; DM decryption demoted to LOW so background DM backfill can't starve feed-driving lists. Test added. Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
1 parent
4bd9503caf
commit
a3b205bfa1
7 files changed
+293
-5
No files matched your search
@@ -57,6 +57,12 @@ import {
|
||||
* are determined by aggregating reports (NIP-56) and mutes (NIP-51) from the user's
|
||||
* trusted social graph (follows).
|
||||
*/
|
||||
|
||||
// Temporary kill-switch for per-video live report subscriptions. Real-env logs
|
||||
// showed these fan out O(videos × relays) and storm relays (~1000 REQ/s),
|
||||
// starving list decryption. Re-enable once batched (single REQ for all ids).
|
||||
const MODERATION_REPORT_SUBS_ENABLED = false;
|
||||
|
||||
export class ModerationService {
|
||||
/**
|
||||
* @param {object} options
|
||||
@@ -191,6 +197,16 @@ export class ModerationService {
|
||||
}
|
||||
|
||||
rebuildTrustedContacts(nextContacts = new Set(), { previous = null } = {}) {
|
||||
// Snapshot the trusted set BEFORE we rebuild so we can detect whether it
|
||||
// actually changed. Emitting "contacts" unconditionally caused a tight loop:
|
||||
// profileModalController listens for "contacts" -> populateFriendsList ->
|
||||
// ensureViewerContactsLoaded -> (empty contacts) -> fetchTrustedContacts ->
|
||||
// clearTrustedMuteTracking -> rebuildTrustedContacts(empty) -> emit again,
|
||||
// spinning the CPU and flooding relays with kind-3 REQs on every login.
|
||||
const priorTrusted =
|
||||
this.trustedContacts instanceof Set
|
||||
? new Set(this.trustedContacts)
|
||||
: new Set();
|
||||
const sanitized = new Set();
|
||||
|
||||
if (nextContacts instanceof Set || Array.isArray(nextContacts)) {
|
||||
@@ -222,8 +238,24 @@ export class ModerationService {
|
||||
this.trustedContacts = seededNext;
|
||||
|
||||
this.updateTrustedSeedOnlyStatus();
|
||||
this.emit("contacts", { size: seededNext.size });
|
||||
this.recomputeAllSummaries();
|
||||
|
||||
// Only notify/recompute when the trusted set actually changed. This breaks
|
||||
// the emit -> fetch -> emit loop above while still firing on real changes
|
||||
// (first population, follows/unfollows, seed updates).
|
||||
let changed = priorTrusted.size !== seededNext.size;
|
||||
if (!changed) {
|
||||
for (const value of seededNext) {
|
||||
if (!priorTrusted.has(value)) {
|
||||
changed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
this.emit("contacts", { size: seededNext.size });
|
||||
this.recomputeAllSummaries();
|
||||
}
|
||||
this.reconcileTrustedMuteSubscriptions(previousContacts, seededNext);
|
||||
}
|
||||
|
||||
@@ -1564,6 +1596,14 @@ export class ModerationService {
|
||||
}
|
||||
|
||||
async setActiveEventIds(ids = []) {
|
||||
// CIRCUIT-BREAKER (confirmed against real env): one live kind-1984 report
|
||||
// subscription PER VIDEO, fanned across ~20 relays and re-issued on every
|
||||
// flaky-relay reconnect, produced ~1000 REQ/s and starved list decryption.
|
||||
// Stays disabled until replaced by a single batched subscription (one REQ
|
||||
// with "#e":[...all ids]) targeting only healthy relays. See refactor plan.
|
||||
if (!MODERATION_REPORT_SUBS_ENABLED) {
|
||||
return;
|
||||
}
|
||||
const nextIds = new Set();
|
||||
if (Array.isArray(ids) || ids instanceof Set) {
|
||||
for (const value of ids) {
|
||||
|
||||
Reference in new issue
Block a user