Skip to content

fix(plex): warm connection before opening SSE to avoid stuck CONNECTING - #1208

Merged
jamcalli merged 2 commits into
developfrom
fix/plex-sse-stale-connection-on-boot
Jun 5, 2026
Merged

fix(plex): warm connection before opening SSE to avoid stuck CONNECTING#1208
jamcalli merged 2 commits into
developfrom
fix/plex-sse-stale-connection-on-boot

Conversation

@jamcalli

@jamcalli jamcalli commented Jun 5, 2026

Copy link
Copy Markdown
Owner

Description

Related Issues

Type of Change

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Performance improvement
  • Code refactoring
  • Documentation update
  • Dependency update

Testing Performed

Screenshots

Checklist

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • My changes work with existing functionality

Summary by CodeRabbit

  • Bug Fixes
    • Improved Plex server connection reliability by performing a pre-connection health probe with a bounded timeout, draining probe responses, and suppressing transient probe failures so normal connections proceed.
    • Made reconnection behavior more resilient by scheduling reconnects in the background to avoid blocking connection setup.

@coderabbitai

coderabbitai Bot commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: 44588392-25aa-47fd-9463-4e05fe3de8d2

📥 Commits

Reviewing files that changed from the base of the PR and between b854224 and c5e9635.

📒 Files selected for processing (1)
  • src/services/plex-server/sse/plex-event-source.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/services/plex-server/sse/plex-event-source.ts

Walkthrough

PlexEventSource now performs an authenticated, timeout-bounded pre-connection probe to /identity via warmConnection() before opening the SSE EventSource. createConnection() is async and awaited by connect(), and reconnection scheduling uses fire-and-forget calls to the async creation flow.

Changes

Plex SSE health probe pre-connection

Layer / File(s) Summary
Health probe constant and warmConnection method
src/services/plex-server/sse/plex-event-source.ts
Adds HEALTH_PROBE_TIMEOUT_MS and warmConnection() which issues an authenticated fetch to /identity with an abort timeout, drains the response body, and logs probe failures while allowing connection setup to continue.
Async createConnection with probe integration
src/services/plex-server/sse/plex-event-source.ts
Refactors createConnection() into an async method that calls warmConnection() before proceeding with EventSource setup and checks for shutdown after warming.
Public connect() and reconnection adapters
src/services/plex-server/sse/plex-event-source.ts
connect() now awaits the async createConnection(). Reconnection timer logic invokes createConnection() via void fire-and-forget to avoid unhandled promises.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • jamcalli/Pulsarr#1077: The config-driven SSE restart in #1077 ultimately re-invokes PlexEventSource.connect(), which now routes through the async createConnection()/warmConnection() probe.
  • jamcalli/Pulsarr#1062: Related refactors around Plex SSE connection status and server reporting that may interact with the new warm/probe behavior.

Suggested labels

fix

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the main change: adding a connection warm-up before opening SSE to prevent stuck CONNECTING state on boot, which aligns with the core objective described in the PR summary.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/plex-sse-stale-connection-on-boot

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
src/services/plex-server/sse/plex-event-source.ts (1)

201-216: 💤 Low value

Consider using AbortSignal.timeout() for cleaner timeout handling.

The existing testConnectionReachability function in connection-cache.ts uses AbortSignal.timeout(timeoutMs) for the same /identity probe pattern. Using that approach here would be more concise and consistent with the codebase.

Also, testConnectionReachability includes X-Plex-Client-Identifier alongside X-Plex-Token. While the probe continues on failure so this isn't critical, adding it would match the established contract.

♻️ Suggested simplification
 private async warmConnection(): Promise<void> {
-  const controller = new AbortController()
-  const timer = setTimeout(() => controller.abort(), HEALTH_PROBE_TIMEOUT_MS)
   try {
     const res = await fetch(`${this.serverUrl}/identity`, {
-      headers: { 'X-Plex-Token': this.token },
-      signal: controller.signal,
+      headers: {
+        'X-Plex-Token': this.token,
+        'X-Plex-Client-Identifier': PLEX_CLIENT_IDENTIFIER,
+      },
+      signal: AbortSignal.timeout(HEALTH_PROBE_TIMEOUT_MS),
     })
     // Drain the response so the connection returns to the pool.
     await res.text()
   } catch {
     this.log.debug('SSE pre-connect health probe failed - continuing')
-  } finally {
-    clearTimeout(timer)
   }
 }

Note: This would require importing PLEX_CLIENT_IDENTIFIER from the appropriate location.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/services/plex-server/sse/plex-event-source.ts` around lines 201 - 216,
Replace the manual AbortController + setTimeout logic in warmConnection with
AbortSignal.timeout(HEALTH_PROBE_TIMEOUT_MS) to simplify timeout handling, and
add the X-Plex-Client-Identifier header (use PLEX_CLIENT_IDENTIFIER constant)
alongside X-Plex-Token when fetching `${this.serverUrl}/identity`; update
imports to bring in PLEX_CLIENT_IDENTIFIER and ensure the fetch uses the
AbortSignal returned by AbortSignal.timeout and still drains the response with
await res.text(), keeping the existing try/catch/finally behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@src/services/plex-server/sse/plex-event-source.ts`:
- Around line 201-216: Replace the manual AbortController + setTimeout logic in
warmConnection with AbortSignal.timeout(HEALTH_PROBE_TIMEOUT_MS) to simplify
timeout handling, and add the X-Plex-Client-Identifier header (use
PLEX_CLIENT_IDENTIFIER constant) alongside X-Plex-Token when fetching
`${this.serverUrl}/identity`; update imports to bring in PLEX_CLIENT_IDENTIFIER
and ensure the fetch uses the AbortSignal returned by AbortSignal.timeout and
still drains the response with await res.text(), keeping the existing
try/catch/finally behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: 72346326-ba90-4f3c-ad73-f1661d8b89e4

📥 Commits

Reviewing files that changed from the base of the PR and between ef43633 and b854224.

📒 Files selected for processing (1)
  • src/services/plex-server/sse/plex-event-source.ts

@jamcalli
jamcalli merged commit 18def9f into develop Jun 5, 2026
8 of 9 checks passed
@jamcalli
jamcalli deleted the fix/plex-sse-stale-connection-on-boot branch June 5, 2026 06:06
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.

1 participant