fix: tolerate hung, refusing and forgetful relays - #198
Merged
Merged
Conversation
…ct storms A relay that accepts the socket and never answers held a subscription's EOSE for about 23 seconds, because each resend restarted nostr-tools' own 8-second wait. The reader is now told history has loaded at that 8-second deadline, whatever a hung relay does. A relay that refused every connection was dialled about 100 times in two minutes of heartbeats, since each publish's retries and the readers they rebound dialled on their own schedules. Dials now share a per-relay backoff (1s doubling to 8s) that only an answer clears, not an open socket; a hung relay drops from 19 dials to 11 and one that drops each socket as it opens from 34 to 18. A publish that raced a socket closing (SendingOnClosedConnection) was taken for the relay refusing it and never retried. It is now a lost connection like any other. A relay that could not be dialled reads "Connection failed" in its health rather than "Publish timed out". Each subscription's seen-id set is bounded; every presence heartbeat is a new id, so a long-lived room grew it without limit. Claude-Session: https://claude.ai/code/session_01CG4pPCsd8pdySNvBpt8fTk
A relay that says OK to a kind 1460 write and never returns it looks healthy by every other measure. The first time a readable relay accepts a regular (stored) kind, the pool asks it for that event by id three seconds later. Only a real EOSE without the event counts: a timeout, a refusal or a dropped socket proves nothing and the kind is tried again on a later write. Write-only relays are never read from. The finding is carried in RelayHealth.unreturned and relay settings shows "Does not keep chat: accepted a message, then did not return it". Claude-Session: https://claude.ai/code/session_01CG4pPCsd8pdySNvBpt8fTk
A hung relay, one that keeps no chat and one that refuses every connection, each beside the local test relay. On the previous pool the refusing relay was dialled 46 times in about 40 seconds; the spec allows 12. Claude-Session: https://claude.ai/code/session_01CG4pPCsd8pdySNvBpt8fTk
# Conflicts: # playwright.config.ts # src/relay-pool.ts
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Evidence-led audit of how the web/desktop app copes with bad relays (hung relay.primal.net, refusing nos.lol, relays that OK chat and keep none). Every 'before' was measured on main and each failing test was checked to fail there.
Already fine and now tested: forged/malformed/flooded events, publish counted on the first OK, outbox keeps unsent messages with Retry.
Tests: typecheck; relay unit tests; new
test/bad-relays.spec.tspasses on chromium and firefox; related specs pass. Overlapssettled()in #196 and the upcoming room-archive branch in src/relay-pool.ts.🤖 Generated with Claude Code
https://claude.ai/code/session_01CG4pPCsd8pdySNvBpt8fTk