feat(session-replay-browser): add flushIntervalConfig to tune rrweb event-split cadence#1744
feat(session-replay-browser): add flushIntervalConfig to tune rrweb event-split cadence#1744lewgordon-amplitude wants to merge 5 commits into
Conversation
…vent-split cadence
Exposes `flushIntervalConfig: { minIntervalMs, maxIntervalMs }` so customers facing
high upfront request volume (and the resulting 200 + X-Session-Replay-Event-Skipped
throttle responses) can raise the cadence without an SDK upgrade for the team.
Defaults are unchanged (500ms / 10s).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Session Replay Browser E2E ResultsDetails
|
…st default bounds If a customer set only `minIntervalMs` higher than the default `MAX_INTERVAL` (10s) (or only `maxIntervalMs` below `MIN_INTERVAL`), the SDK's class-field default would silently clamp the effective interval, negating the customer's tune-up. Sanitization now cross-checks against effective bounds and raises/lowers the unspecified side to match the user-supplied value, with a logger warning. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
bugbot run |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
1 issue from previous review remains unresolved.
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit c1d3f4e. Configure here.
…st split Class-field initializer `private interval = this.minInterval` ran before the constructor body, freezing `interval` at the class-field default (500ms) regardless of `args.minInterval`. Moved the assignment into the constructor body after the override, so a customer setting `flushIntervalConfig.minIntervalMs: 5000` actually gets a 5s wait before the first split — instead of the burst this PR was meant to prevent. Adds regression tests verifying first-split behavior. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
bugbot run |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Autofix Details
Bugbot Autofix prepared a fix for the issue found in the latest run.
- ✅ Fixed: Infinity for maxIntervalMs clamps to floor, creating maximum aggression
- Separated non-finite value handling to clamp Infinity to MAX_INTERVAL instead of MIN_FLUSH_INTERVAL_FLOOR_MS, preserving the intent of 'no cap' for maximum intervals.
Or push these changes by commenting:
@cursor push 9407c5a6ac
Preview (9407c5a6ac)
diff --git a/packages/session-replay-browser/src/config/local-config.ts b/packages/session-replay-browser/src/config/local-config.ts
--- a/packages/session-replay-browser/src/config/local-config.ts
+++ b/packages/session-replay-browser/src/config/local-config.ts
@@ -134,8 +134,15 @@
}
}
if (raw.maxIntervalMs !== undefined) {
- if (!Number.isFinite(raw.maxIntervalMs) || raw.maxIntervalMs < MIN_FLUSH_INTERVAL_FLOOR_MS) {
+ if (!Number.isFinite(raw.maxIntervalMs)) {
+ // For maxIntervalMs, Infinity means "no cap" — clamp to MAX_INTERVAL to preserve that intent.
+ // NaN is invalid and also gets the large-default treatment for a maximum bound.
loggerProvider.warn(
+ `flushIntervalConfig.maxIntervalMs ${raw.maxIntervalMs} is not finite; clamping to ${MAX_INTERVAL}ms.`,
+ );
+ sanitized.maxIntervalMs = MAX_INTERVAL;
+ } else if (raw.maxIntervalMs < MIN_FLUSH_INTERVAL_FLOOR_MS) {
+ loggerProvider.warn(
`flushIntervalConfig.maxIntervalMs ${raw.maxIntervalMs} is below floor ${MIN_FLUSH_INTERVAL_FLOOR_MS}ms; clamping.`,
);
sanitized.maxIntervalMs = MIN_FLUSH_INTERVAL_FLOOR_MS;You can send follow-ups to the cloud agent here.
…no upper bound" Previously `!Number.isFinite()` clamped Infinity to the 100ms floor — directly inverting the customer's intent. Math.min(Infinity, x) === x is well-defined in BaseEventsStore.shouldSplitEventsList, so Infinity is a valid "no cap on growth" sentinel. Validator now rejects only NaN and sub-floor numbers for max; min still clamps Infinity (where "never split" is also broken). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
bugbot run |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit c5d8d09. Configure here.
Adds Playwright spec covering full real-browser SDK init with the new option: custom min/max delivers events on explicit flush, Infinity max is accepted, and sub-floor min is clamped without aborting init. Also threads PLAYWRIGHT_BASE_URL through e2e/playwright.config.ts so the suite can target a non-default port, and teaches sr-capture-test.html to read flushIntervalConfig from URL params. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>


Summary
Adds
flushIntervalConfig: { minIntervalMs, maxIntervalMs }toSessionReplayLocalConfigso customers (or specific deployments) can raise the rrweb event-split cadence without waiting on an SDK upgrade.Context
Even after SR-4280 landed (honoring
X-Session-Replay-Event-Skippedserver back-pressure), we're still seeing significant 200+throttle traffic on v1.30.2. Walking the splitting logic (BaseEventsStore.shouldSplitEventsList) explains why:MIN_INTERVAL = 500msand grows by 500ms after each split, capped atMAX_INTERVAL = 10s.flushPauseUntilMsdoesn't dampen the upfront burst. The throttle pause only affects the next schedule, not in-flight or already-queued contexts.flushPauseUntilMsandkilledSessionsare in-memory and per-instance, so every fresh page load / SDK init repeats the burst from scratch.This PR doesn't touch the defaults — it just exposes the knob. We can roll out higher values for specific high-volume customers (or recommend tuning for self-hosted standalone integrations) without shipping a behavior change to everyone.
What's in here
flushIntervalConfig?: FlushIntervalConfigonSessionReplayLocalConfig, withminIntervalMsandmaxIntervalMsfields (both optional).SessionReplayLocalConfig— clamps non-finite or sub-100ms values, raisesmaxto matchminif a caller inverts them, warns via the configured logger.createEventsManager('replay')(theinteractionmanager already had its ownINTERACTION_MIN_INTERVALplumbing).test/config/local-config.test.tscovering defaults, custom values, clamping, and inversion.session-replay.test.tsverifying the values flow intocreateEventsManager.Test plan
pnpm --filter @amplitude/session-replay-browser build— cleannpx jest --testPathIgnorePatterns=e2e— 915/915 pass, 100% coveragepnpm lint:eslint/pnpm lint:prettier— clean (warnings are pre-existing, unrelated files)minIntervalMs(e.g., 3000ms) on a heavy-traffic test page and confirm the early-burst request count drops as expectedFollow-ups (not in this PR)
MIN_INTERVALonce we have data on customer impact of the new knob.flushPauseUntilMs/killedSessionsto localStorage keyed by API key, so cold starts honor the server's last directive instead of re-discovering it.🤖 Generated with Claude Code
Note
Medium Risk
Introduces new customer-facing tuning for replay flush cadence and fixes a timing initialization regression that affects when the first event split occurs, which can change request patterns in production. Changes are guarded behind optional config but touch core event batching/splitting behavior.
Overview
Adds
flushIntervalConfig(minIntervalMs/maxIntervalMs) toSessionReplayLocalConfigto let callers tune rrweb event-split/flush cadence, including sanitization (100ms floor,Infinitysupport for max, and min/max cross-validation with warnings).Wires the config through
SessionReplayintocreateEventsManager('replay'), and fixesBaseEventsStoreso the first split interval correctly honors caller-suppliedminInterval(not the class-field default).Adds unit/integration coverage for the validator and forwarding behavior, plus Playwright e2e tests and a configurable Playwright
baseURL; updates the SR capture test page to accept interval params via querystring.Reviewed by Cursor Bugbot for commit ce43e66. Bugbot is set up for automated code reviews on this repo. Configure here.