Skip to content

fix(nostr): clear relay publish timers to prevent leaks and unhandled rejections#39742

Closed
Bortlesboat wants to merge 1 commit into
openclaw:mainfrom
Bortlesboat:fix/nostr-profile-timer-leak
Closed

fix(nostr): clear relay publish timers to prevent leaks and unhandled rejections#39742
Bortlesboat wants to merge 1 commit into
openclaw:mainfrom
Bortlesboat:fix/nostr-profile-timer-leak

Conversation

@Bortlesboat

Copy link
Copy Markdown
Contributor

Summary

  • publishProfileEvent() uses Promise.race with a setTimeout-based timeout per relay. When pool.publish() resolves first, the pending timer fires later and rejects a promise nobody is listening to, causing an unhandledRejection event in strict Node.js environments.
  • importProfileFromRelays() creates both an overall timeout timer and per-relay subscription cleanup timers that continue running even when all relays respond before the deadline.

This stores timer handles and clears them in finally blocks so timers are always cleaned up regardless of which side wins the race.

Changes

  • nostr-profile.ts: Track setTimeout handle per relay, clearTimeout in finally
  • nostr-profile-import.ts: Track overall + per-relay timers, clear all in finally

Test plan

  • All 288 existing Nostr extension tests pass (npx vitest run extensions/nostr/src/)
  • No functional behavior change — only timer cleanup added

… rejections

publishProfileEvent() uses Promise.race with a setTimeout-based timeout
promise per relay.  When pool.publish() wins the race, the pending
setTimeout fires later and rejects a promise nobody is listening to,
causing an unhandled promise rejection in strict Node environments.

Similarly, importProfileFromRelays() creates both an overall timeout
timer and per-relay subscription cleanup timers that continue running
even when all relays respond before the deadline.

Store timer handles and clear them in finally blocks so timers are
always cleaned up regardless of which side wins the race.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
@openclaw-barnacle openclaw-barnacle Bot added channel: nostr Channel integration: nostr size: XS labels Mar 8, 2026
@greptile-apps

greptile-apps Bot commented Mar 8, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes two timer leak issues in the Nostr extension:

  1. nostr-profile.ts (publishProfileEvent): Stores the per-relay timeout handle and clears it in a finally block. This prevents unhandled promise rejections when pool.publish() resolves before the timeout fires.

  2. nostr-profile-import.ts (importProfileFromRelays): Stores both the overall timeout handle and an array of per-relay subscription cleanup timers, then clears all of them in the inner finally block. This ensures timers don't fire after the race concludes, and also prevents them from running after pool.close(relays) has been called in the outer finally.

Both changes are minimal, non-functional, and preserve the existing safety nets (e.g., pool.close(relays) still runs to clean up subscriptions). All 288 existing tests pass.

Confidence Score: 5/5

  • This PR is safe to merge — it makes targeted, minimal changes to fix timer leaks with no functional behavior changes.
  • The changes are small, well-scoped, and correct: timer handles are properly stored and cleared in finally blocks, ensuring cleanup regardless of which promise wins the race. The existing safety net (pool.close) remains intact. All 288 existing tests pass, and no new code paths are introduced.
  • No files require special attention.

Last reviewed commit: 9de9afd

@Bortlesboat

Copy link
Copy Markdown
Contributor Author

Closing — no maintainer engagement after 12 days. Happy to reopen if there's interest.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

channel: nostr Channel integration: nostr size: XS

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant