Route reads to a single relay (round-robin) for fast EOSE resolution

Previously reqRouter sent every query to all 3 read relays, meaning
NPool.query() had to wait for all relays to coordinate before resolving.
The slowest relay dictated the feed speed.

Now reads go to one relay at a time, rotating round-robin across the
configured read relays. Each query resolves as soon as that single relay
sends EOSE — no waiting on the other two. Publishing still fans out to
all write relays.

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
This commit is contained in:
shakespeare.diy
2026-02-17 03:18:33 -06:00
parent 5babdf6fa0
commit cf193abfd9
+10 -7
View File
@@ -26,6 +26,9 @@ const NostrProvider: React.FC<NostrProviderProps> = (props) => {
queryClient.invalidateQueries({ queryKey: ['nostr'] });
}, [config.relayMetadata, queryClient]);
// Round-robin index for distributing reads across relays
const rrIndex = useRef(0);
// Initialize NPool only once
if (!pool.current) {
pool.current = new NPool({
@@ -35,26 +38,26 @@ const NostrProvider: React.FC<NostrProviderProps> = (props) => {
reqRouter(filters: NostrFilter[]) {
const routes = new Map<string, NostrFilter[]>();
// Route to all read relays
// Pick a single read relay (round-robin) so queries resolve on first EOSE
const readRelays = relayMetadata.current.relays
.filter(r => r.read)
.map(r => r.url);
for (const url of readRelays) {
routes.set(url, filters);
if (readRelays.length > 0) {
const idx = rrIndex.current % readRelays.length;
rrIndex.current = idx + 1;
routes.set(readRelays[idx], filters);
}
return routes;
},
eventRouter(_event: NostrEvent) {
// Get write relays from metadata
// Publish to all write relays
const writeRelays = relayMetadata.current.relays
.filter(r => r.write)
.map(r => r.url);
const allRelays = new Set<string>(writeRelays);
return [...allRelays];
return [...new Set(writeRelays)];
},
});
}