mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-27 07:52:24 +00:00
Merge pull request #2075 from PR0M3TH3AN/fix/nostr-count-timeout-12537375718680249854
fix(nostr): prevent count timeouts from disconnecting relays
This commit is contained in:
2 files changed
+69
-3
No files matched your search
+12
-3
@@ -8608,9 +8608,18 @@ export class NostrClient {
|
||||
this.countUnsupportedRelays.add(url);
|
||||
} else {
|
||||
logRelayCountFailure(url, error);
|
||||
this.markRelayUnreachable(url, 60000, {
|
||||
reason: isTimeout ? "count-timeout" : "count-error",
|
||||
});
|
||||
// If the count request timed out, we don't want to kill the entire relay connection
|
||||
// because it might still be good for subscriptions.
|
||||
// We only trip the circuit breaker for hard errors.
|
||||
if (!isTimeout) {
|
||||
this.markRelayUnreachable(url, 60000, {
|
||||
reason: "count-error",
|
||||
});
|
||||
} else if (isDevMode) {
|
||||
devLogger.warn(
|
||||
`[nostr] Relay ${url} count timed out (ignored for circuit breaker).`
|
||||
);
|
||||
}
|
||||
}
|
||||
return {
|
||||
url,
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
|
||||
import { test } from "node:test";
|
||||
import assert from "node:assert";
|
||||
import { NostrClient } from "../../js/nostr/client.js";
|
||||
|
||||
// Mock global objects if needed
|
||||
if (!globalThis.localStorage) {
|
||||
globalThis.localStorage = {
|
||||
getItem: () => null,
|
||||
setItem: () => {},
|
||||
removeItem: () => {},
|
||||
};
|
||||
}
|
||||
|
||||
test("NostrClient resilience to COUNT timeouts", async (t) => {
|
||||
const client = new NostrClient();
|
||||
const relayUrl = "wss://slow.relay.example";
|
||||
client.relays = [relayUrl];
|
||||
|
||||
// Mock the pool
|
||||
client.pool = {
|
||||
ensureRelay: async (url) => {
|
||||
return {
|
||||
url,
|
||||
count: async () => {
|
||||
// Simulate timeout by waiting longer than the client's timeout
|
||||
await new Promise(r => setTimeout(r, 100));
|
||||
// In the real code, withRequestTimeout throws the error, the relay just hangs or returns late.
|
||||
// But here we can simulate the client's wrapper throwing 'count-timeout'
|
||||
// Actually, client.sendRawCountFrame handles the timeout wrapping.
|
||||
// So we just need a promise that hangs.
|
||||
return new Promise(() => {});
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
// We need to override getRequestTimeoutMs to be very short for the test
|
||||
client.getRequestTimeoutMs = () => 10; // 10ms timeout
|
||||
|
||||
// Verify initial state
|
||||
assert.strictEqual(client.unreachableRelays.has(relayUrl), false);
|
||||
|
||||
// Trigger the count
|
||||
await client.countEventsAcrossRelays([{ kinds: [1] }]);
|
||||
|
||||
// Check if relay was marked unreachable
|
||||
// logic:
|
||||
// 1. sendRawCountFrame calls withRequestTimeout
|
||||
// 2. timeouts after 10ms -> throws 'count-timeout'
|
||||
// 3. countEventsAcrossRelays catches 'count-timeout'
|
||||
// 4. currently calls markRelayUnreachable
|
||||
|
||||
const isUnreachable = client.unreachableRelays.has(relayUrl);
|
||||
|
||||
assert.strictEqual(isUnreachable, false, "Relay should NOT be marked unreachable after count timeout");
|
||||
});
|
||||
Reference in new issue
Block a user