Unified · Split
| @@ -328,7 +328,14 @@ export function useConnectionHealth(connection: Connection): { · 327 unmodified lines | ||
| 328 | 328 | // freshness window, not the floor, is what suppressed it). |
| 329 | 329 | const delay = autoProbeRetryDelayMs(key); |
| 330 | 330 | if (delay === null) return; |
| 331 | + // The decision is NOT final while the timer is pending: roll the epoch | |
| 332 | + // back to "unseen" so an effect rerun (a new `connection` identity from a | |
| 333 | + // list refetch, a scope change) that cancels this timer re-enters the | |
| 334 | + // decision above and re-arms it, instead of treating the epoch as already | |
| 335 | + // handled and leaving the row suppressed until the next remount. | |
| 336 | + seenEpoch.current = undefined; | |
| 331 | 337 | const timer = setTimeout(() => { |
| 338 | + seenEpoch.current = epoch; | |
| 332 | 339 | if (shouldAutoProbe(key, last)) probe(); |
| 333 | 340 | }, delay); |
| 334 | 341 | return () => clearTimeout(timer); |
| @@ -433,11 +440,16 @@ export function useConnectionsHealth( · 98 unmodified lines | ||
| 433 | 440 | probe(); |
| 434 | 441 | continue; |
| 435 | 442 | } |
| 436 | − // Same bounded suppression as the single-connection hook. | |
| 443 | + // Same bounded suppression as the single-connection hook, and the same | |
| 444 | + // rule for a pending timer: the row is NOT yet considered for this | |
| 445 | + // epoch, so a rerun (the list re-merging as owners' rows arrive) that | |
| 446 | + // clears the timers re-enters the decision and re-arms it. | |
| 437 | 447 | const delay = autoProbeRetryDelayMs(memoryKey); |
| 438 | 448 | if (delay === null) continue; |
| 449 | + revalidated.current.delete(key); | |
| 439 | 450 | timers.push( |
| 440 | 451 | setTimeout(() => { |
| 452 | + revalidated.current.set(key, epoch); | |
| 441 | 453 | if (shouldAutoProbe(memoryKey, last)) probe(); |
| 442 | 454 | }, delay), |
| 443 | 455 | ); |