Skip to content

fix(api): make TeslemetryStream.close() abort the active SSE stream - #83

Merged
Bre77 merged 1 commit into
mainfrom
fm/tsapi-stream-close-abort
Aug 2, 2026
Merged

fix(api): make TeslemetryStream.close() abort the active SSE stream#83
Bre77 merged 1 commit into
mainfrom
fm/tsapi-stream-close-abort

Conversation

@Bre77

@Bre77 Bre77 commented Aug 2, 2026

Copy link
Copy Markdown
Member

Intent

  • TeslemetryStream.close() only set active = false; the in-flight SSE fetch/reader and any pending reconnect backoff timer (up to 10 minutes) kept running past teardown, leaking HTTP streams and timers on reinit.
    • connect() now creates a per-connection AbortController and threads its signal into the generated SSE client's signal option and into the reconnect backoff wait, so close() can cancel both immediately instead of waiting for them to time out or fire.
    • close()/disconnect() are now async and resolve once _connectLoop has fully exited, so callers can await close() before reconnecting without a leak window.
    • Added tests: closing during an active stream aborts the fetch/reader, closing during a backoff wait cancels the pending timer without firing a reconnect, and connect() after close() reinitializes cleanly.
  • Added a changeset (patch bump for @teslemetry/api) per the repo's release flow.
    • Follow-up: once this publishes, bump the homey app's @teslemetry/api pin and reinstall/build/test against it. Not done here - the homey app lives in a separate repo, and the new version doesn't exist on npm until this merges and the changesets release flow runs.

close() previously only flipped active=false; the in-flight fetch/reader
and any pending reconnect backoff timer (up to 10 min) kept running,
leaking HTTP streams and timers on teardown/reinit. close()/disconnect()
now abort via a per-connect AbortController shared by the fetch signal
and the backoff wait, and are awaitable so callers can sequence
teardown before reconnecting.
@Bre77 Bre77 added the fm Opened by a Firstmate crewmate label Aug 2, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5bce234bd9

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +312 to +313
this.abortController = new AbortController();
this.loopPromise = this._connectLoop(this.abortController.signal);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Prevent reconnects before the prior loop exits

When a caller uses the formerly synchronous API as close(); connect() without awaiting the new close promise, connect() sets the shared active flag back to true before the aborted old loop resumes. That old _connectLoop then keeps iterating with its permanently aborted signal; each generated SSE stream ends immediately, so the outer loop can spin continuously, emit spurious connect events, consume CPU, and prevent the close promise from settling while the new loop also runs. Serialize reconnects or make loop continuation depend on per-loop ownership rather than the shared active flag.

Useful? React with 👍 / 👎.

@Bre77
Bre77 merged commit c170974 into main Aug 2, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

fm Opened by a Firstmate crewmate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant