Skip to content

Clean up pending resolvers without matching response - #714

Open
jowgn wants to merge 1 commit into
codetheweb:masterfrom
jowgn:bugfix-pending-resolvers
Open

jowgn wants to merge 1 commit into
codetheweb:masterfrom
jowgn:bugfix-pending-resolvers

Conversation

@jowgn

@jowgn jowgn commented Nov 11, 2026

Copy link
Copy Markdown

Fixes #713.

Some devices (seen with a protocol 3.5 EV wallbox) answer a query with a different sequence number. The resolver registered in _send() is then never called or deleted, so every get() leaves a pending promise, a p-retry operation and the buffers held by their closures in memory. Polling such a device every 30 s grew the heap by about 7 MB/h until the host ran out of memory (details and heap snapshot numbers in #713).

Change

  • _send() now removes its resolver after _responseTimeout * 5 seconds (10 s with the default) if no matching response arrived, and resolves the request with undefined. The timer is cleared when a matching response arrives and is unref'd, so it never keeps the process alive.
  • The received data is still emitted as data event, so event-based users are not affected. Callers awaiting get()/refresh() now get undefined instead of a promise that never settles.
  • Resolving instead of rejecting avoids a retry storm: a rejection would make p-retry re-send the request up to 5 times.

Tests

  • Two new tests in test/stub.js: the resolver is removed and the request resolves when no matching response arrives, and a matching response still resolves with its payload. The first test fails without this change.
  • npm run lint passes (only the two existing complexity warnings), npm test passes (41 tests) on Node.js 22.
  • The same change has been running on our device since 10 Nov; memory has stayed flat since then (it previously grew by about 7 MB/h).

🤖 Generated with Claude Code

https://claude.ai/code/session_01JWPUonRpUEqKFU4NRAdEtK

Devices using protocol 3.5 may answer a query with a different
sequence number. The resolver registered in _send() was then never
called or deleted, so every get() left a pending promise, a p-retry
operation and the related buffers in memory (see codetheweb#713).

Remove the resolver after _responseTimeout * 5 seconds and resolve the
request with undefined. The data itself is still emitted as `data`
event.

Fixes codetheweb#713

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JWPUonRpUEqKFU4NRAdEtK

This branch has not been deployed

No deployments
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.

Memory leak: _resolvers entries are never removed when a protocol 3.5 device answers get() with a different sequence number

1 participant