mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-11-04 20:02:26 +00:00
fix(subscriptions): guard the subscription-list refresh loop
The live subscription-list subscription (kind 30000) delivers our OWN list event back through handleSubscriptionListEvent, which called updateFromRelays on EVERY event. updateFromRelays re-fetches the list, the relay echoes the same event through the live sub, and the handler fires again — a self-sustaining loop that floods the cold-login burst with redundant kind-30000 REQs (the kind 30000=19 storm in the real-env console, KNOWN_BUGS #0). Same shape as the contact-list emit→fetch→emit loop fixed earlier. Add an emit-on-change guard: skip the refresh when the event is one we've already acted on (by id — matters during the pre-decrypt login window where subsEventCreatedAt isn't set yet) or is not newer than what we've applied. A genuinely newer list event still refreshes exactly once. Also extend the channel-sim harness to capture per-filter REQ signatures and kind-30000 REQ timing, which is how this loop was isolated. Test: tests/subscriptions-manager.test.mjs — echo of the same event id does not re-refresh; an older event is ignored; a newer event refreshes once. Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
1 parent
1f07538c66
commit
10ea4f6a22
3 files changed
+77
No files matched your search
@@ -209,6 +209,8 @@ async function main() {
|
||||
dmHelpersUnavailable: 0,
|
||||
};
|
||||
const reqBurst = {}; // kind -> count, captured during the login window
|
||||
const reqSig = {}; // filter signature -> count, to surface redundant queries
|
||||
const subsReqTimes = []; // ms-since-login of each kind-30000 REQ (redundancy timing)
|
||||
let loginAt = Date.now();
|
||||
let measuringReq = true;
|
||||
|
||||
@@ -238,6 +240,10 @@ async function main() {
|
||||
const msg = JSON.parse(p);
|
||||
for (const f of msg.slice(2)) {
|
||||
for (const k of f.kinds || ["?"]) reqBurst[k] = (reqBurst[k] || 0) + 1;
|
||||
const otherKeys = Object.keys(f).filter((x) => x !== "kinds" && x !== "authors").sort().join(",");
|
||||
const sig = `kinds=${(f.kinds || []).join("|")}${otherKeys ? " " + otherKeys : ""}${f.authors ? " authors=" + f.authors.length : ""}`;
|
||||
reqSig[sig] = (reqSig[sig] || 0) + 1;
|
||||
if ((f.kinds || []).includes(30000)) subsReqTimes.push(Date.now() - loginAt);
|
||||
}
|
||||
} catch (_) {}
|
||||
});
|
||||
@@ -298,6 +304,10 @@ async function main() {
|
||||
report(`time -> signer-ready : ${signals.signerReadyAt ?? "NEVER"} ms`);
|
||||
report(`time -> lists-sync done: ${signals.listsSyncCompleteAt ?? "NEVER"} ms`);
|
||||
report(`login REQ burst (~10s) : ${reqTotal} frames [${reqTop}]`);
|
||||
const sigTop = Object.entries(reqSig).sort((a, b) => b[1] - a[1]).slice(0, 12);
|
||||
report("top REQ filters (count → filter):");
|
||||
for (const [sig, n] of sigTop) report(` ${String(n).padStart(4)} ${sig}`);
|
||||
report(`kind-30000 REQ times(ms): [${subsReqTimes.join(", ")}]`);
|
||||
report(`decrypt timeouts logged: ${signals.decryptTimeouts}`);
|
||||
report(`channel drops injected : ${drops}`);
|
||||
report(`breaker opened / recov : ${signals.breakerOpened} / ${signals.breakerRecovered}`);
|
||||
|
||||
Reference in new issue
Block a user