mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-27 07:52:24 +00:00
perf: bound relay background concurrency to 3
Replaces unbounded `Promise.all(relays.map(...))` calls with `pMap` using a concurrency limit of 3 for background operations like history hydration, metadata fetching, and DM sending. This prevents network saturation and potential main-thread jank when many relays are configured. Includes benchmark verification script `benchmarks/relay_concurrency_repro.mjs`. Audited upload docs and confirmed accuracy. Co-authored-by: PR0M3TH3AN <[email protected]>
This commit is contained in:
1 parent
0607367f1a
commit
d3fa684e45
9 files changed
+234
-17
No files matched your search
@@ -0,0 +1,101 @@
|
||||
import { NostrClient } from "../js/nostr/client.js";
|
||||
import { pMap } from "../js/utils/asyncUtils.js";
|
||||
|
||||
// Mock globals for Node environment
|
||||
globalThis.WebSocket = class MockWebSocket {};
|
||||
globalThis.localStorage = {
|
||||
getItem: () => null,
|
||||
setItem: () => {},
|
||||
removeItem: () => {},
|
||||
clear: () => {}
|
||||
};
|
||||
globalThis.indexedDB = {
|
||||
open: () => ({
|
||||
result: {
|
||||
createObjectStore: () => {},
|
||||
transaction: () => ({ objectStore: () => ({ get: () => {}, put: () => {} }) })
|
||||
},
|
||||
onupgradeneeded: () => {},
|
||||
onsuccess: () => {}
|
||||
})
|
||||
};
|
||||
|
||||
// Mock dependencies
|
||||
class MockPool {
|
||||
constructor() {
|
||||
this.activeRequests = 0;
|
||||
this.maxConcurrent = 0;
|
||||
}
|
||||
|
||||
async list(relays, filters) {
|
||||
this.activeRequests++;
|
||||
if (this.activeRequests > this.maxConcurrent) {
|
||||
this.maxConcurrent = this.activeRequests;
|
||||
}
|
||||
|
||||
// Simulate network delay
|
||||
await new Promise(resolve => setTimeout(resolve, 50));
|
||||
|
||||
this.activeRequests--;
|
||||
return [];
|
||||
}
|
||||
|
||||
async get(relays, filter) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
async function runBenchmark() {
|
||||
console.log("Starting Relay Concurrency Benchmark...");
|
||||
|
||||
const client = new NostrClient();
|
||||
const mockPool = new MockPool();
|
||||
client.pool = mockPool;
|
||||
|
||||
// Simulate 20 relays
|
||||
const relays = Array.from({ length: 20 }, (_, i) => `wss://relay${i}.example.com`);
|
||||
client.relays = relays;
|
||||
client.readRelays = relays;
|
||||
|
||||
// 1. Benchmark fetchAndCacheNip71Metadata
|
||||
console.log("\nTesting fetchAndCacheNip71Metadata with 20 relays...");
|
||||
mockPool.maxConcurrent = 0;
|
||||
|
||||
const pointerMap = new Map();
|
||||
pointerMap.set("e:123", { type: "e", value: "123", relays: [] });
|
||||
|
||||
await client.fetchAndCacheNip71Metadata(pointerMap, ["e:123"]);
|
||||
|
||||
console.log(`Max concurrent requests: ${mockPool.maxConcurrent}`);
|
||||
if (mockPool.maxConcurrent > 5) {
|
||||
console.log("FAIL: Concurrency is unbounded!");
|
||||
} else {
|
||||
console.log("PASS: Concurrency is bounded.");
|
||||
}
|
||||
|
||||
// 2. Benchmark hydrateVideoHistory
|
||||
console.log("\nTesting hydrateVideoHistory with 20 relays...");
|
||||
mockPool.maxConcurrent = 0;
|
||||
|
||||
const video = {
|
||||
id: "v1",
|
||||
videoRootId: "root1",
|
||||
tags: [["d", "d1"]],
|
||||
pubkey: "pub1"
|
||||
};
|
||||
|
||||
// Prime local cache to force relay fetch
|
||||
// We need to simulate that we found <= 1 version locally
|
||||
client.allEvents.set("v1", video);
|
||||
|
||||
await client.hydrateVideoHistory(video);
|
||||
|
||||
console.log(`Max concurrent requests: ${mockPool.maxConcurrent}`);
|
||||
if (mockPool.maxConcurrent > 5) {
|
||||
console.log("FAIL: Concurrency is unbounded!");
|
||||
} else {
|
||||
console.log("PASS: Concurrency is bounded.");
|
||||
}
|
||||
}
|
||||
|
||||
runBenchmark().catch(console.error);
|
||||
Reference in new issue
Block a user