Skip to content

Commit 9185d3b

Browse files
committed
feat(replay): Add experimental option to allow for a checkout every 6 minutes
Including more checkouts will improve replayer scrubbing since it will reduce the number of mutations that need to be processed (especially for longer replays). The downside is that it will increase the size of replays since we will have up to 9 more snapshots per replay (max replay duration is 60 minutes / 6 minute checkouts).
1 parent 5c03ac5 commit 9185d3b

File tree

3 files changed

+28
-7
lines changed

3 files changed

+28
-7
lines changed

packages/replay-internal/src/replay.ts

+15-1
Original file line numberDiff line numberDiff line change
@@ -376,7 +376,19 @@ export class ReplayContainer implements ReplayContainerInterface {
376376
// When running in error sampling mode, we need to overwrite `checkoutEveryNms`
377377
// Without this, it would record forever, until an error happens, which we don't want
378378
// instead, we'll always keep the last 60 seconds of replay before an error happened
379-
...(this.recordingMode === 'buffer' && { checkoutEveryNms: BUFFER_CHECKOUT_TIME }),
379+
...(this.recordingMode === 'buffer'
380+
? { checkoutEveryNms: BUFFER_CHECKOUT_TIME }
381+
: // Otherwise, use experimental option w/ min checkout time of 6 minutes
382+
// This is to improve playback seeking as there could potentially be
383+
// less mutations to process in the worse cases.
384+
//
385+
// checkout by "N" events is probably ideal, but means we have less
386+
// control about the number of checkouts we make (which generally
387+
// increases replay size)
388+
this._options._experiments.continuousCheckout && {
389+
// Minimum checkout time is 6 minutes
390+
checkoutEveryNms: Math.min(360_000, this._options._experiments.continuousCheckout),
391+
}),
380392
emit: getHandleRecordingEmit(this),
381393
onMutation: this._onMutationHandler,
382394
...(canvasOptions
@@ -388,6 +400,8 @@ export class ReplayContainer implements ReplayContainerInterface {
388400
}
389401
: {}),
390402
});
403+
404+
console.log('continuousCheckout', this._options._experiments);
391405
} catch (err) {
392406
this._handleException(err);
393407
}

packages/replay-internal/src/types/replay.ts

+1
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,7 @@ export interface ReplayPluginOptions extends ReplayNetworkOptions {
232232
_experiments: Partial<{
233233
captureExceptions: boolean;
234234
traceInternals: boolean;
235+
continuousCheckout: number;
235236
}>;
236237
}
237238

packages/replay-internal/src/util/handleRecordingEmit.ts

+12-6
Original file line numberDiff line numberDiff line change
@@ -59,38 +59,44 @@ export function getHandleRecordingEmit(replay: ReplayContainer): RecordingEmitCa
5959
return false;
6060
}
6161

62+
const session = replay.session;
63+
6264
// Additionally, create a meta event that will capture certain SDK settings.
6365
// In order to handle buffer mode, this needs to either be done when we
64-
// receive checkout events or at flush time.
66+
// receive checkout events or at flush time. We have an experimental mode
67+
// to perform multiple checkouts a session (the idea is to improve
68+
// seeking during playback), so also only include if segmentId is 0.
6569
//
6670
// `isCheckout` is always true, but want to be explicit that it should
6771
// only be added for checkouts
68-
addSettingsEvent(replay, isCheckout);
72+
if (session && session.segmentId === 0) {
73+
addSettingsEvent(replay, isCheckout);
74+
}
6975

7076
// If there is a previousSessionId after a full snapshot occurs, then
7177
// the replay session was started due to session expiration. The new session
7278
// is started before triggering a new checkout and contains the id
7379
// of the previous session. Do not immediately flush in this case
7480
// to avoid capturing only the checkout and instead the replay will
7581
// be captured if they perform any follow-up actions.
76-
if (replay.session && replay.session.previousSessionId) {
82+
if (session && session.previousSessionId) {
7783
return true;
7884
}
7985

8086
// When in buffer mode, make sure we adjust the session started date to the current earliest event of the buffer
8187
// this should usually be the timestamp of the checkout event, but to be safe...
82-
if (replay.recordingMode === 'buffer' && replay.session && replay.eventBuffer) {
88+
if (replay.recordingMode === 'buffer' && session && replay.eventBuffer) {
8389
const earliestEvent = replay.eventBuffer.getEarliestTimestamp();
8490
if (earliestEvent) {
8591
logInfo(
8692
`[Replay] Updating session start time to earliest event in buffer to ${new Date(earliestEvent)}`,
8793
replay.getOptions()._experiments.traceInternals,
8894
);
8995

90-
replay.session.started = earliestEvent;
96+
session.started = earliestEvent;
9197

9298
if (replay.getOptions().stickySession) {
93-
saveSession(replay.session);
99+
saveSession(session);
94100
}
95101
}
96102
}

0 commit comments

Comments
 (0)