Skip to content

Commit bc10756

Browse files
committed
use shouldRefreshSession instead of isSessionExpired
1 parent 2aa9c1e commit bc10756

3 files changed

Lines changed: 58 additions & 8 deletions

File tree

packages/replay-internal/src/coreHandlers/handleGlobalEvent.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { saveSession } from '../session/saveSession';
44
import type { ReplayContainer } from '../types';
55
import { isErrorEvent, isFeedbackEvent, isReplayEvent, isTransactionEvent } from '../util/eventUtils';
66
import { isRrwebError } from '../util/isRrwebError';
7-
import { isSessionExpired } from '../util/isSessionExpired';
7+
import { shouldRefreshSession } from '../session/shouldRefreshSession';
88
import { debug } from '../util/logger';
99
import { resetReplayIdOnDynamicSamplingContext } from '../util/resetReplayIdOnDynamicSamplingContext';
1010
import { addFeedbackBreadcrumb } from './util/addFeedbackBreadcrumb';
@@ -16,14 +16,14 @@ import { shouldSampleForBufferEvent } from './util/shouldSampleForBufferEvent';
1616
export function handleGlobalEventListener(replay: ReplayContainer): (event: Event, hint: EventHint) => Event | null {
1717
return Object.assign(
1818
(event: Event, hint: EventHint) => {
19-
// Aggressively check for expired session and clean stale replay_id from DSC.
19+
// Check for expired session and clean stale replay_id from DSC.
2020
// This must run BEFORE the isEnabled/isPaused guards because when paused,
21-
// the guards short-circuit without cleaning DSC. The cached DSC on the scope
22-
// (set by browserTracingIntegration when the idle span ended) persists the
23-
// stale replay_id indefinitely until explicitly deleted.
21+
// the guards short-circuit without cleaning DSC. Uses shouldRefreshSession
22+
// instead of isSessionExpired to respect the buffer-mode carve-out:
23+
// buffer sessions with segmentId === 0 are kept alive even when time-expired.
2424
if (
2525
replay.session &&
26-
isSessionExpired(replay.session, {
26+
shouldRefreshSession(replay.session, {
2727
maxReplayDuration: replay.getOptions().maxReplayDuration,
2828
sessionIdleExpire: replay.timeouts.sessionIdleExpire,
2929
})

packages/replay-internal/src/replay.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@ import { debounce } from './util/debounce';
5050
import { getRecordingSamplingOptions } from './util/getRecordingSamplingOptions';
5151
import { getHandleRecordingEmit } from './util/handleRecordingEmit';
5252
import { isExpired } from './util/isExpired';
53-
import { isSessionExpired } from './util/isSessionExpired';
5453
import { debug } from './util/logger';
5554
import {
5655
resetReplayIdOnDynamicSamplingContext,
@@ -1011,7 +1010,7 @@ export class ReplayContainer implements ReplayContainerInterface {
10111010
return;
10121011
}
10131012

1014-
const expired = isSessionExpired(this.session, {
1013+
const expired = shouldRefreshSession(this.session, {
10151014
maxReplayDuration: this._options.maxReplayDuration,
10161015
sessionIdleExpire: this.timeouts.sessionIdleExpire,
10171016
});

packages/replay-internal/test/integration/coreHandlers/handleGlobalEvent.test.ts

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -511,6 +511,57 @@ describe('Integration | coreHandlers | handleGlobalEvent', () => {
511511
expect(resetReplayIdSpy).toHaveBeenCalledTimes(1);
512512
});
513513

514+
it('does not reset replayId on DSC for expired buffer session with segmentId 0', () => {
515+
const now = Date.now();
516+
517+
replay.session = makeSession({
518+
id: 'test-session-id',
519+
segmentId: 0,
520+
lastActivity: now - SESSION_IDLE_EXPIRE_DURATION - 1,
521+
started: now - SESSION_IDLE_EXPIRE_DURATION - 1,
522+
sampled: 'buffer',
523+
});
524+
525+
replay['_isPaused'] = true;
526+
527+
const resetReplayIdSpy = vi.spyOn(
528+
resetReplayIdOnDynamicSamplingContextModule,
529+
'resetReplayIdOnDynamicSamplingContext',
530+
);
531+
532+
const errorEvent = Error();
533+
handleGlobalEventListener(replay)(errorEvent, {});
534+
535+
// Should NOT reset DSC: buffer sessions with segmentId 0 are kept alive
536+
// even when time-expired (shouldRefreshSession carve-out)
537+
expect(resetReplayIdSpy).not.toHaveBeenCalled();
538+
});
539+
540+
it('resets replayId on DSC for expired buffer session with segmentId > 0', () => {
541+
const now = Date.now();
542+
543+
replay.session = makeSession({
544+
id: 'test-session-id',
545+
segmentId: 1,
546+
lastActivity: now - SESSION_IDLE_EXPIRE_DURATION - 1,
547+
started: now - SESSION_IDLE_EXPIRE_DURATION - 1,
548+
sampled: 'buffer',
549+
});
550+
551+
replay['_isPaused'] = true;
552+
553+
const resetReplayIdSpy = vi.spyOn(
554+
resetReplayIdOnDynamicSamplingContextModule,
555+
'resetReplayIdOnDynamicSamplingContext',
556+
);
557+
558+
const errorEvent = Error();
559+
handleGlobalEventListener(replay)(errorEvent, {});
560+
561+
// Buffer session with segmentId > 0 that is expired SHOULD have DSC reset
562+
expect(resetReplayIdSpy).toHaveBeenCalledTimes(1);
563+
});
564+
514565
it('resets replayId on DSC when replay is disabled and session has expired', () => {
515566
const now = Date.now();
516567

0 commit comments

Comments
 (0)