@@ -90,9 +90,7 @@ export const NOSTR_KINDS = {
9090export const DEFAULT_RELAYS = [
9191 'wss://relay.damus.io' ,
9292 'wss://nos.lol' ,
93- 'wss://relay.nostr.band' ,
9493 'wss://nostr-pub.wellorder.net' ,
95- 'wss://relay.current.fyi' ,
9694]
9795
9896// Connection states
@@ -109,8 +107,10 @@ const RETRY_CONFIG = {
109107 baseDelay : 1000 , // 1 second base delay
110108 maxDelay : 30000 , // 30 second max delay
111109 backoffFactor : 2 , // Double delay each retry
112- maxRetries : 6 , // Max 6 retries before giving up
110+ maxRetries : 5 , // Max 5 retries before giving up on this connection cycle
113111 jitterFactor : 0.1 , // 10% jitter to prevent thundering herd
112+ maxFailureCycles : 3 , // After 3 complete failure cycles, disable relay temporarily
113+ disabledRelayTimeout : 300000 , // Re-enable disabled relays after 5 minutes
114114}
115115
116116// ========================================================================
@@ -831,6 +831,7 @@ export class NostrSyncService {
831831 // State
832832 this . connections = new Map ( ) // relay URL -> connection info
833833 this . subscriptions = new Map ( ) // subscription ID -> subscription info
834+ this . disabledRelays = new Map ( ) // relay URL -> timestamp when disabled
834835 this . eventQueue = [ ] // Queued events for when connections are restored
835836 this . isInitialized = false
836837 this . nostrKeypair = null
@@ -1553,28 +1554,50 @@ export class NostrSyncService {
15531554 // Private methods
15541555
15551556 async _connectToRelay ( relayUrl ) {
1556- if ( this . connections . has ( relayUrl ) ) {
1557- const conn = this . connections . get ( relayUrl )
1558- if ( conn . state === CONNECTION_STATES . CONNECTED ||
1559- conn . state === CONNECTION_STATES . CONNECTING ) {
1557+ // Check if relay is temporarily disabled
1558+ if ( this . disabledRelays && this . disabledRelays . has ( relayUrl ) ) {
1559+ const disabledAt = this . disabledRelays . get ( relayUrl )
1560+ if ( Date . now ( ) - disabledAt < RETRY_CONFIG . disabledRelayTimeout ) {
1561+ this . _log ( `Relay ${ relayUrl } is temporarily disabled, skipping` )
1562+ return
1563+ }
1564+ // Re-enable relay after timeout
1565+ this . disabledRelays . delete ( relayUrl )
1566+ this . _log ( `Re-enabling relay ${ relayUrl } after timeout` )
1567+ }
1568+
1569+ const existingConn = this . connections . get ( relayUrl )
1570+ if ( existingConn ) {
1571+ if ( existingConn . state === CONNECTION_STATES . CONNECTED ||
1572+ existingConn . state === CONNECTION_STATES . CONNECTING ) {
15601573 return // Already connected or connecting
15611574 }
15621575 }
15631576
15641577 this . _log ( `Connecting to relay: ${ relayUrl } ` )
15651578
1566- const connection = {
1579+ // Preserve retryCount and failureCycles if reconnecting, otherwise create new connection
1580+ const connection = existingConn ? {
1581+ ...existingConn ,
1582+ ws : null ,
1583+ state : CONNECTION_STATES . CONNECTING ,
1584+ connectedAt : null ,
1585+ lastError : null
1586+ // retryCount and failureCycles preserved from existingConn
1587+ } : {
15671588 url : relayUrl ,
15681589 ws : null ,
15691590 state : CONNECTION_STATES . CONNECTING ,
15701591 retryCount : 0 ,
1592+ failureCycles : 0 ,
15711593 retryTimeout : null ,
15721594 connectedAt : null ,
15731595 lastError : null
15741596 }
15751597
15761598 this . connections . set ( relayUrl , connection )
1577- this . _notifyConnectionChange ( relayUrl , CONNECTION_STATES . DISCONNECTED , CONNECTION_STATES . CONNECTING )
1599+ const oldState = existingConn ? existingConn . state : CONNECTION_STATES . DISCONNECTED
1600+ this . _notifyConnectionChange ( relayUrl , oldState , CONNECTION_STATES . CONNECTING )
15781601
15791602 try {
15801603 const ws = new WebSocket ( relayUrl )
@@ -1623,6 +1646,7 @@ export class NostrSyncService {
16231646 connection . state = CONNECTION_STATES . CONNECTED
16241647 connection . connectedAt = Date . now ( )
16251648 connection . retryCount = 0 // Reset retry count on successful connection
1649+ connection . failureCycles = 0 // Reset failure cycles on successful connection
16261650 connection . lastError = null
16271651
16281652 this . _log ( `Connected to relay: ${ relayUrl } ` )
@@ -1745,8 +1769,22 @@ export class NostrSyncService {
17451769 connection . retryCount ++
17461770
17471771 if ( connection . retryCount > RETRY_CONFIG . maxRetries ) {
1748- this . _log ( `Max retries exceeded for ${ relayUrl } , giving up` )
1749- return
1772+ // Completed a full retry cycle without success
1773+ connection . failureCycles = ( connection . failureCycles || 0 ) + 1
1774+ connection . retryCount = 0 // Reset for next cycle
1775+
1776+ if ( connection . failureCycles >= RETRY_CONFIG . maxFailureCycles ) {
1777+ this . _log ( `Relay ${ relayUrl } failed ${ connection . failureCycles } cycles, temporarily disabling` )
1778+ // Initialize disabledRelays map if needed
1779+ if ( ! this . disabledRelays ) {
1780+ this . disabledRelays = new Map ( )
1781+ }
1782+ this . disabledRelays . set ( relayUrl , Date . now ( ) )
1783+ connection . state = CONNECTION_STATES . DISCONNECTED
1784+ return
1785+ }
1786+
1787+ this . _log ( `Max retries exceeded for ${ relayUrl } , starting cycle ${ connection . failureCycles + 1 } ` )
17501788 }
17511789
17521790 // Calculate delay with exponential backoff and jitter
@@ -1758,7 +1796,7 @@ export class NostrSyncService {
17581796 const jitter = baseDelay * RETRY_CONFIG . jitterFactor * ( Math . random ( ) - 0.5 )
17591797 const delay = Math . max ( baseDelay + jitter , 100 ) // Minimum 100ms delay
17601798
1761- this . _log ( `Scheduling reconnect to ${ relayUrl } in ${ Math . round ( delay ) } ms (attempt ${ connection . retryCount } )` )
1799+ this . _log ( `Scheduling reconnect to ${ relayUrl } in ${ Math . round ( delay ) } ms (attempt ${ connection . retryCount } , cycle ${ ( connection . failureCycles || 0 ) + 1 } )` )
17621800
17631801 connection . retryTimeout = setTimeout ( async ( ) => {
17641802 connection . state = CONNECTION_STATES . RECONNECTING
0 commit comments