Skip to content

fix: end client before removeAllListeners in stop() to prevent subscribe() hang#173

Closed
kibae wants to merge 8 commits into
mainfrom
fix/stop-subscribe-hang
Closed

fix: end client before removeAllListeners in stop() to prevent subscribe() hang#173
kibae wants to merge 8 commits into
mainfrom
fix/stop-subscribe-hang

Conversation

@kibae
Copy link
Copy Markdown
Owner

@kibae kibae commented Apr 21, 2026

Fixes #172

Problem

When stop() was called, removeAllListeners() stripped the end/error handlers from the pg client before client.end() was called. This caused the subscribe() promise to never resolve or reject — hanging the caller indefinitely.

Fix

Call client.end() first, then remove listeners. This ensures the pg query promise inside subscribe() is properly notified when the connection closes.

// Before (broken)
this._client?.removeAllListeners(); // removes end handler
await this._client?.end();          // nobody listening → hang

// After (fixed)
await this._client?.end();          // closes connection, promise resolves
this._client?.removeAllListeners(); // clean up after

kibae added 2 commits April 21, 2026 23:12
…ibe() hang

When stop() was called, removeAllListeners() was removing the end/error
handlers from the pg client before client.end() was called. This caused
the subscribe() promise (which awaits plugin.start()) to never resolve
or reject, hanging the caller indefinitely.

Fix: call client.end() first, then remove listeners.

Fixes #172
@holomekc
Copy link
Copy Markdown

Wow this was lightning fast! Thx <3

kibae added 6 commits April 21, 2026 23:22
…unexpected disconnect

Adds _intentionalStop flag to distinguish between:
- stop() called explicitly: subscribe() promise resolves cleanly (no throw)
- unexpected disconnect: subscribe() promise rejects, error event emitted

This prevents the proc() retry pattern from spinning when stop() is called,
while preserving error handling for real connection failures.
…be() on stop()

Instead of reordering client.end() which caused 'Connection terminated' errors,
use a deferred promise that stop() resolves to signal subscribe() to return cleanly.

- stop() calls _stopResolve() before closing the connection
- subscribe() races plugin.start() against the stop signal
- Unexpected disconnects still propagate as errors via the catch block
- No breaking changes to existing code patterns
@kibae kibae closed this Apr 21, 2026
@kibae kibae deleted the fix/stop-subscribe-hang branch April 21, 2026 14:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

stop() causes subscribe() promise to never resolve

2 participants