Skip to content

✨ Pulse open WebSocket vitals on a shared heartbeat - #5095

Open
bdibon wants to merge 9 commits into
boris.dibon/websocket-vitals-3-closingfrom
boris.dibon/websocket-vitals-4-pulse
Open

bdibon wants to merge 9 commits into
boris.dibon/websocket-vitals-3-closingfrom
boris.dibon/websocket-vitals-4-pulse

Conversation

@bdibon

@bdibon bdibon commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

Motivation

A connection held open for an hour is invisible until it closes, and one that dies without a close event reports nothing about the traffic it carried. Open connections now report where they are on a heartbeat.

Part of the WebSocket vitals stack. Every PR targets the previous one; the first one targets the boris.dibon/websocket-vitals integration branch, which is merged into main in one go once the whole stack is approved. #5055 stays open as the reference implementation: the tip of this stack is content-identical to it, rebased on the current main.

  1. 🔧 Pin rum-events-format and add WebSocket test utilities #5092 🔧 Pin rum-events-format and add WebSocket test utilities
  2. ✨ Collect connecting, open and closed WebSocket vitals #5093 ✨ Collect connecting, open and closed WebSocket vitals
  3. ✨ Report the websocket_closing vital #5094 ✨ Report the websocket_closing vital
  4. ✨ Pulse open WebSocket vitals on a shared heartbeat #5095 ✨ Pulse open WebSocket vitals on a shared heartbeat 👈 this PR
  5. ✨ Report WebSocket silences and send queue depth, and protect WebSocket vitals in beforeSend #5096 ✨ Report WebSocket silences and send queue depth, and protect WebSocket vitals in beforeSend
  6. ✨ End WebSocket tracking when the page is discarded #5097 ✨ End WebSocket tracking when the page is discarded

Changes

Commit by commit:

  • ✨ Date open WebSocket vitals at their pulse: recordPulse() dates the next open vital and bumps the snapshot version it rides on. The first open vital is dated at the open event; a pulse outside the open phase is ignored.
  • ✨ Pulse open WebSocket vitals on a shared heartbeat: every WEBSOCKET_HEARTBEAT_INTERVAL (1 min, the rate Chrome throttles hidden tabs' timers to), every connection in phase open emits a new websocket_open vital. One timer serves every connection and only runs while one is open; a closing connection falls silent, so a hung close stops looking alive.
  • ✨ Pulse open WebSocket vitals when the page is hidden, frozen or unloading: on PREPARE_URGENT_FLUSH, so the traffic is sent before the page is frozen or lost. On mobile, hidden is the only signal guaranteed at that point.
  • ✅ Cover the WebSocket heartbeat end to end

Test instructions

  • Unit: yarn test:unit --spec "packages/browser-rum-core/src/domain/webSocket/*.spec.ts" --spec packages/browser-rum-core/src/browser/webSocketObservable.spec.ts
  • E2E: yarn test:e2e -g "rum websockets"

Note

check-staging-merge is expected to fail: staging-40 already contains the earlier merge of #5055, which touches the same files. It clears at the next staging bump; the other checks should be green.

Checklist

  • Tested locally
  • Tested on staging
  • Added unit tests for this change.
  • Added e2e/integration tests for this change.
  • Updated documentation and/or relevant AGENTS.md file

@bdibon bdibon mentioned this pull request Oct 1, 2026
3 of 5 tasks
@datadog-datadog-prod-us1-2

datadog-datadog-prod-us1-2 Bot commented Oct 1, 2026 •

Copy link
Copy Markdown

Pipelines  Tests

❌ Errors

Your PR has failed checks. Please review the issues below and take necessary action before merging.

🚦 1 Pipeline job failed

DataDog/browser-sdk | check-staging-merge

View more details · View in GitLab

ℹ️ Info

No other issues found (see more)

🧪 All tests passed
❄️ No new flaky tests detected

🎯 Code Coverage (details)
• Patch Coverage: 80.65%
• Overall Coverage: 77.38% (+0.01%)

Useful? React with 👍 / 👎

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: e050cd3 | Docs | View more details | Give us feedback!

@cit-pr-commenter-54b7da

cit-pr-commenter-54b7da Bot commented Oct 1, 2026 •

Copy link
Copy Markdown

Bundles Sizes Evolution

📦 Bundle Name Base Size Local Size 𝚫 𝚫% Status
Rum Salesforce N/A 186.81 KiB N/A N/A N/A
Rum 186.30 KiB 186.79 KiB +501 B +0.26% ✅
Rum-salesforce Profiler N/A 8.35 KiB N/A N/A N/A
Rum Profiler 8.35 KiB 8.35 KiB 0 B 0.00% ✅
Rum-salesforce Recorder N/A 31.94 KiB N/A N/A N/A
Rum Recorder 31.94 KiB 31.94 KiB 0 B 0.00% ✅
Logs 59.00 KiB 59.00 KiB 0 B 0.00% ✅
Rum Slim 144.29 KiB 144.75 KiB +480 B +0.32% ✅
Worker 22.96 KiB 22.96 KiB 0 B 0.00% ✅
Rum Shopify N/A 217.20 KiB N/A N/A N/A
Rum-shopify Profiler N/A 8.35 KiB N/A N/A N/A
Rum-shopify Recorder N/A 4.77 KiB N/A N/A N/A

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 1, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-07T16:18:32.129134Z e050cd3 New commits
ℹ️ 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

Comment on lines +98 to +99
case 'open':
return state.openClocks
return state.pulseClocks

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

💬 suggestion: ‏Looking at that, I guess we could maybe remove the pulse concept.

  • pulseClocks -> openClocks
  • recordPulse -> updateOpen

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I think we need the openClocks to record the timeToFirstMessage, for example:
connection opens at T0 -> no messages... -> heartbeat pulses, the openClocks would then change -> a message is sent or received -> timeToFirstMessage is computed from openClocks which is actually pulseClocks

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I will rename it to reportClocks, to be coherent with your next comments

Comment thread packages/browser-rum-core/src/domain/webSocket/webSocketCollection.ts Outdated
Comment thread packages/browser-rum-core/src/domain/webSocket/webSocketCollection.ts Outdated
bdibon and others added 7 commits October 7, 2026 15:15
An open connection can now be reported again at a later pulse: recordPulse dates its next open vital and bumps the snapshot version it rides on. The first open vital is dated at the open event; a pulse outside the open phase is ignored.

Co-authored-by: Cursor <cursoragent@cursor.com>
Every WEBSOCKET_HEARTBEAT_INTERVAL (one minute), each connection in phase open reports a new websocket_open vital with the next snapshot version, so a long-lived connection is visible while it is open. One timer serves every connection, and only runs while one is open; a closing connection falls silent.

Co-authored-by: Cursor <cursoragent@cursor.com>
…ading

A background transition is the only signal mobile browsers guarantee before a page goes away, and a connection may not survive it. Open connections report a pulse on every PREPARE_URGENT_FLUSH, so the traffic they carried is sent before the page is frozen or lost.

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
@bdibon
bdibon force-pushed the boris.dibon/websocket-vitals-4-pulse branch from 1d9542c to 2b63be9 Compare October 7, 2026 14:28
@bdibon
bdibon requested a review from bcaudan October 7, 2026 15:04
Comment thread packages/browser-rum-core/src/domain/webSocket/webSocketCollection.ts Outdated
Comment thread packages/browser-rum-core/src/domain/webSocket/trackedConnection.ts Outdated
Comment thread packages/browser-rum-core/src/domain/webSocket/webSocketCollection.ts Outdated

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.

2 participants