Skip to content

Commit 50e3a5e

Browse files
committed
ref(replay): Use SESSION_IDLE_DURATION instead of VISIBILITY_CHANGE_TIMEOUT
1 parent 70abc37 commit 50e3a5e

File tree

10 files changed

+40
-50
lines changed

10 files changed

+40
-50
lines changed

packages/replay/src/constants.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,6 @@ export const UNABLE_TO_SEND_REPLAY = 'Unable to send Replay';
1414
// The idle limit for a session
1515
export const SESSION_IDLE_DURATION = 300_000; // 5 minutes in ms
1616

17-
// Grace period to keep a session when a user changes tabs or hides window
18-
export const VISIBILITY_CHANGE_TIMEOUT = SESSION_IDLE_DURATION;
19-
2017
// The maximum length of a session
2118
export const MAX_SESSION_LIFE = 3_600_000; // 60 minutes
2219

packages/replay/src/replay.ts

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,7 @@ import { captureException, getCurrentHub } from '@sentry/core';
44
import type { Breadcrumb, ReplayRecordingMode } from '@sentry/types';
55
import { logger } from '@sentry/utils';
66

7-
import {
8-
ERROR_CHECKOUT_TIME,
9-
MAX_SESSION_LIFE,
10-
SESSION_IDLE_DURATION,
11-
VISIBILITY_CHANGE_TIMEOUT,
12-
WINDOW,
13-
} from './constants';
7+
import { ERROR_CHECKOUT_TIME, MAX_SESSION_LIFE, SESSION_IDLE_DURATION, WINDOW } from './constants';
148
import { setupPerformanceObserver } from './coreHandlers/performanceObserver';
159
import { createEventBuffer } from './eventBuffer';
1610
import { getSession } from './session/getSession';
@@ -367,7 +361,7 @@ export class ReplayContainer implements ReplayContainerInterface {
367361
* Returns true if session is not expired, false otherwise.
368362
* @hidden
369363
*/
370-
public checkAndHandleExpiredSession(expiry?: number): boolean | void {
364+
public checkAndHandleExpiredSession(): boolean | void {
371365
const oldSessionId = this.getSessionId();
372366

373367
// Prevent starting a new session if the last user activity is older than
@@ -382,7 +376,7 @@ export class ReplayContainer implements ReplayContainerInterface {
382376

383377
// --- There is recent user activity --- //
384378
// This will create a new session if expired, based on expiry length
385-
if (!this._loadAndCheckSession(expiry)) {
379+
if (!this._loadAndCheckSession()) {
386380
return;
387381
}
388382

@@ -412,9 +406,9 @@ export class ReplayContainer implements ReplayContainerInterface {
412406
* Loads (or refreshes) the current session.
413407
* Returns false if session is not recorded.
414408
*/
415-
private _loadAndCheckSession(expiry = SESSION_IDLE_DURATION): boolean {
409+
private _loadAndCheckSession(): boolean {
416410
const { type, session } = getSession({
417-
expiry,
411+
expiry: SESSION_IDLE_DURATION,
418412
stickySession: Boolean(this._options.stickySession),
419413
currentSession: this.session,
420414
sessionSampleRate: this._options.sessionSampleRate,
@@ -626,7 +620,7 @@ export class ReplayContainer implements ReplayContainerInterface {
626620
return;
627621
}
628622

629-
const expired = isSessionExpired(this.session, VISIBILITY_CHANGE_TIMEOUT);
623+
const expired = isSessionExpired(this.session, SESSION_IDLE_DURATION);
630624

631625
if (breadcrumb && !expired) {
632626
this._createCustomBreadcrumb(breadcrumb);
@@ -646,10 +640,10 @@ export class ReplayContainer implements ReplayContainerInterface {
646640
return;
647641
}
648642

649-
const isSessionActive = this.checkAndHandleExpiredSession(VISIBILITY_CHANGE_TIMEOUT);
643+
const isSessionActive = this.checkAndHandleExpiredSession();
650644

651645
if (!isSessionActive) {
652-
// If the user has come back to the page within VISIBILITY_CHANGE_TIMEOUT
646+
// If the user has come back to the page within SESSION_IDLE_DURATION
653647
// ms, we will re-use the existing session, otherwise create a new
654648
// session
655649
__DEBUG_BUILD__ && logger.log('[Replay] Document has become active, but session has expired');

packages/replay/test/integration/errorSampleRate.test.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import {
55
ERROR_CHECKOUT_TIME,
66
MAX_SESSION_LIFE,
77
REPLAY_SESSION_KEY,
8-
VISIBILITY_CHANGE_TIMEOUT,
8+
SESSION_IDLE_DURATION,
99
WINDOW,
1010
} from '../../src/constants';
1111
import type { ReplayContainer } from '../../src/replay';
@@ -154,15 +154,15 @@ describe('Integration | errorSampleRate', () => {
154154
});
155155
});
156156

157-
it('does not send a replay when triggering a full dom snapshot when document becomes visible after [VISIBILITY_CHANGE_TIMEOUT]ms', async () => {
157+
it('does not send a replay when triggering a full dom snapshot when document becomes visible after [SESSION_IDLE_DURATION]ms', async () => {
158158
Object.defineProperty(document, 'visibilityState', {
159159
configurable: true,
160160
get: function () {
161161
return 'visible';
162162
},
163163
});
164164

165-
jest.advanceTimersByTime(VISIBILITY_CHANGE_TIMEOUT + 1);
165+
jest.advanceTimersByTime(SESSION_IDLE_DURATION + 1);
166166

167167
document.dispatchEvent(new Event('visibilitychange'));
168168

@@ -186,8 +186,8 @@ describe('Integration | errorSampleRate', () => {
186186

187187
expect(replay).not.toHaveLastSentReplay();
188188

189-
// User comes back before `VISIBILITY_CHANGE_TIMEOUT` elapses
190-
jest.advanceTimersByTime(VISIBILITY_CHANGE_TIMEOUT - 100);
189+
// User comes back before `SESSION_IDLE_DURATION` elapses
190+
jest.advanceTimersByTime(SESSION_IDLE_DURATION - 100);
191191
Object.defineProperty(document, 'visibilityState', {
192192
configurable: true,
193193
get: function () {

packages/replay/test/integration/events.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ describe('Integration | events', () => {
4040
// Create a new session and clear mocks because a segment (from initial
4141
// checkout) will have already been uploaded by the time the tests run
4242
clearSession(replay);
43-
replay['_loadAndCheckSession'](0);
43+
replay['_loadAndCheckSession']();
4444
mockTransportSend.mockClear();
4545
});
4646

@@ -93,7 +93,7 @@ describe('Integration | events', () => {
9393

9494
it('has correct timestamps when there are events earlier than initial timestamp', async function () {
9595
clearSession(replay);
96-
replay['_loadAndCheckSession'](0);
96+
replay['_loadAndCheckSession']();
9797
mockTransportSend.mockClear();
9898
Object.defineProperty(document, 'visibilityState', {
9999
configurable: true,

packages/replay/test/integration/flush.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import * as SentryUtils from '@sentry/utils';
22

3-
import { DEFAULT_FLUSH_MIN_DELAY, SESSION_IDLE_DURATION, WINDOW } from '../../src/constants';
3+
import { DEFAULT_FLUSH_MIN_DELAY, WINDOW } from '../../src/constants';
44
import type { ReplayContainer } from '../../src/replay';
55
import type { EventBuffer } from '../../src/types';
66
import * as AddMemoryEntry from '../../src/util/addMemoryEntry';
@@ -95,7 +95,7 @@ describe('Integration | flush', () => {
9595
jest.setSystemTime(new Date(BASE_TIMESTAMP));
9696
sessionStorage.clear();
9797
clearSession(replay);
98-
replay['_loadAndCheckSession'](SESSION_IDLE_DURATION);
98+
replay['_loadAndCheckSession']();
9999
mockRecord.takeFullSnapshot.mockClear();
100100
Object.defineProperty(WINDOW, 'location', {
101101
value: prevLocation,

packages/replay/test/integration/rateLimiting.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { getCurrentHub } from '@sentry/core';
22
import type { Transport } from '@sentry/types';
33

4-
import { DEFAULT_FLUSH_MIN_DELAY, SESSION_IDLE_DURATION } from '../../src/constants';
4+
import { DEFAULT_FLUSH_MIN_DELAY } from '../../src/constants';
55
import type { ReplayContainer } from '../../src/replay';
66
import * as SendReplayRequest from '../../src/util/sendReplayRequest';
77
import { BASE_TIMESTAMP, mockSdk } from '../index';
@@ -46,7 +46,7 @@ describe('Integration | rate-limiting behaviour', () => {
4646
// Create a new session and clear mocks because a segment (from initial
4747
// checkout) will have already been uploaded by the time the tests run
4848
clearSession(replay);
49-
replay['_loadAndCheckSession'](0);
49+
replay['_loadAndCheckSession']();
5050

5151
mockSendReplayRequest.mockClear();
5252
});
@@ -57,7 +57,7 @@ describe('Integration | rate-limiting behaviour', () => {
5757
jest.setSystemTime(new Date(BASE_TIMESTAMP));
5858
clearSession(replay);
5959
jest.clearAllMocks();
60-
replay['_loadAndCheckSession'](SESSION_IDLE_DURATION);
60+
replay['_loadAndCheckSession']();
6161
});
6262

6363
afterAll(() => {

packages/replay/test/integration/sendReplayEvent.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import * as SentryCore from '@sentry/core';
22
import type { Transport } from '@sentry/types';
33
import * as SentryUtils from '@sentry/utils';
44

5-
import { DEFAULT_FLUSH_MIN_DELAY, SESSION_IDLE_DURATION, WINDOW } from '../../src/constants';
5+
import { DEFAULT_FLUSH_MIN_DELAY, WINDOW } from '../../src/constants';
66
import type { ReplayContainer } from '../../src/replay';
77
import { addEvent } from '../../src/util/addEvent';
88
import * as SendReplayRequest from '../../src/util/sendReplayRequest';
@@ -59,7 +59,7 @@ describe('Integration | sendReplayEvent', () => {
5959
// Create a new session and clear mocks because a segment (from initial
6060
// checkout) will have already been uploaded by the time the tests run
6161
clearSession(replay);
62-
replay['_loadAndCheckSession'](0);
62+
replay['_loadAndCheckSession']();
6363

6464
mockSendReplayRequest.mockClear();
6565
});
@@ -69,7 +69,7 @@ describe('Integration | sendReplayEvent', () => {
6969
await new Promise(process.nextTick);
7070
jest.setSystemTime(new Date(BASE_TIMESTAMP));
7171
clearSession(replay);
72-
replay['_loadAndCheckSession'](SESSION_IDLE_DURATION);
72+
replay['_loadAndCheckSession']();
7373
});
7474

7575
afterAll(() => {

packages/replay/test/integration/session.test.ts

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import {
55
DEFAULT_FLUSH_MIN_DELAY,
66
MAX_SESSION_LIFE,
77
REPLAY_SESSION_KEY,
8-
VISIBILITY_CHANGE_TIMEOUT,
8+
SESSION_IDLE_DURATION,
99
WINDOW,
1010
} from '../../src/constants';
1111
import type { ReplayContainer } from '../../src/replay';
@@ -55,7 +55,7 @@ describe('Integration | session', () => {
5555
});
5656
});
5757

58-
it('creates a new session and triggers a full dom snapshot when document becomes visible after [VISIBILITY_CHANGE_TIMEOUT]ms', () => {
58+
it('creates a new session and triggers a full dom snapshot when document becomes visible after [SESSION_IDLE_DURATION]ms', () => {
5959
Object.defineProperty(document, 'visibilityState', {
6060
configurable: true,
6161
get: function () {
@@ -65,7 +65,7 @@ describe('Integration | session', () => {
6565

6666
const initialSession = replay.session;
6767

68-
jest.advanceTimersByTime(VISIBILITY_CHANGE_TIMEOUT + 1);
68+
jest.advanceTimersByTime(SESSION_IDLE_DURATION + 1);
6969

7070
document.dispatchEvent(new Event('visibilitychange'));
7171

@@ -75,7 +75,7 @@ describe('Integration | session', () => {
7575
expect(replay).not.toHaveSameSession(initialSession);
7676
});
7777

78-
it('does not create a new session if user hides the tab and comes back within [VISIBILITY_CHANGE_TIMEOUT] seconds', () => {
78+
it('does not create a new session if user hides the tab and comes back within [SESSION_IDLE_DURATION] seconds', () => {
7979
const initialSession = replay.session;
8080

8181
Object.defineProperty(document, 'visibilityState', {
@@ -88,8 +88,8 @@ describe('Integration | session', () => {
8888
expect(mockRecord.takeFullSnapshot).not.toHaveBeenCalled();
8989
expect(replay).toHaveSameSession(initialSession);
9090

91-
// User comes back before `VISIBILITY_CHANGE_TIMEOUT` elapses
92-
jest.advanceTimersByTime(VISIBILITY_CHANGE_TIMEOUT - 1);
91+
// User comes back before `SESSION_IDLE_DURATION` elapses
92+
jest.advanceTimersByTime(SESSION_IDLE_DURATION - 1);
9393
Object.defineProperty(document, 'visibilityState', {
9494
configurable: true,
9595
get: function () {
@@ -184,7 +184,7 @@ describe('Integration | session', () => {
184184
expect(replay.session).toBe(undefined);
185185
});
186186

187-
it('creates a new session and triggers a full dom snapshot when document becomes visible after [VISIBILITY_CHANGE_TIMEOUT]ms', () => {
187+
it('creates a new session and triggers a full dom snapshot when document becomes visible after [SESSION_IDLE_DURATION]ms', () => {
188188
Object.defineProperty(document, 'visibilityState', {
189189
configurable: true,
190190
get: function () {
@@ -194,7 +194,7 @@ describe('Integration | session', () => {
194194

195195
const initialSession = replay.session;
196196

197-
jest.advanceTimersByTime(VISIBILITY_CHANGE_TIMEOUT + 1);
197+
jest.advanceTimersByTime(SESSION_IDLE_DURATION + 1);
198198

199199
document.dispatchEvent(new Event('visibilitychange'));
200200

@@ -204,7 +204,7 @@ describe('Integration | session', () => {
204204
expect(replay).not.toHaveSameSession(initialSession);
205205
});
206206

207-
it('creates a new session and triggers a full dom snapshot when document becomes focused after [VISIBILITY_CHANGE_TIMEOUT]ms', () => {
207+
it('creates a new session and triggers a full dom snapshot when document becomes focused after [SESSION_IDLE_DURATION]ms', () => {
208208
Object.defineProperty(document, 'visibilityState', {
209209
configurable: true,
210210
get: function () {
@@ -214,7 +214,7 @@ describe('Integration | session', () => {
214214

215215
const initialSession = replay.session;
216216

217-
jest.advanceTimersByTime(VISIBILITY_CHANGE_TIMEOUT + 1);
217+
jest.advanceTimersByTime(SESSION_IDLE_DURATION + 1);
218218

219219
WINDOW.dispatchEvent(new Event('focus'));
220220

@@ -224,7 +224,7 @@ describe('Integration | session', () => {
224224
expect(replay).not.toHaveSameSession(initialSession);
225225
});
226226

227-
it('does not create a new session if user hides the tab and comes back within [VISIBILITY_CHANGE_TIMEOUT] seconds', () => {
227+
it('does not create a new session if user hides the tab and comes back within [SESSION_IDLE_DURATION] seconds', () => {
228228
const initialSession = replay.session;
229229

230230
Object.defineProperty(document, 'visibilityState', {
@@ -237,8 +237,8 @@ describe('Integration | session', () => {
237237
expect(mockRecord.takeFullSnapshot).not.toHaveBeenCalled();
238238
expect(replay).toHaveSameSession(initialSession);
239239

240-
// User comes back before `VISIBILITY_CHANGE_TIMEOUT` elapses
241-
jest.advanceTimersByTime(VISIBILITY_CHANGE_TIMEOUT - 1);
240+
// User comes back before `SESSION_IDLE_DURATION` elapses
241+
jest.advanceTimersByTime(SESSION_IDLE_DURATION - 1);
242242
Object.defineProperty(document, 'visibilityState', {
243243
configurable: true,
244244
get: function () {
@@ -451,7 +451,7 @@ describe('Integration | session', () => {
451451

452452
it('increases segment id after each event', async () => {
453453
clearSession(replay);
454-
replay['_loadAndCheckSession'](0);
454+
replay['_loadAndCheckSession']();
455455

456456
Object.defineProperty(document, 'visibilityState', {
457457
configurable: true,

packages/replay/test/integration/stop.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import * as SentryUtils from '@sentry/utils';
22

33
import type { Replay } from '../../src';
4-
import { SESSION_IDLE_DURATION, WINDOW } from '../../src/constants';
4+
import { WINDOW } from '../../src/constants';
55
import type { ReplayContainer } from '../../src/replay';
66
import { addEvent } from '../../src/util/addEvent';
77
// mock functions need to be imported first
@@ -44,7 +44,7 @@ describe('Integration | stop', () => {
4444
jest.setSystemTime(new Date(BASE_TIMESTAMP));
4545
sessionStorage.clear();
4646
clearSession(replay);
47-
replay['_loadAndCheckSession'](SESSION_IDLE_DURATION);
47+
replay['_loadAndCheckSession']();
4848
mockRecord.takeFullSnapshot.mockClear();
4949
mockAddInstrumentationHandler.mockClear();
5050
Object.defineProperty(WINDOW, 'location', {

packages/replay/test/utils/setupReplayContainer.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { SESSION_IDLE_DURATION } from '../../src/constants';
21
import { createEventBuffer } from '../../src/eventBuffer';
32
import { ReplayContainer } from '../../src/replay';
43
import type { RecordingOptions, ReplayPluginOptions } from '../../src/types';
@@ -28,7 +27,7 @@ export function setupReplayContainer({
2827

2928
clearSession(replay);
3029
replay['_setInitialState']();
31-
replay['_loadAndCheckSession'](SESSION_IDLE_DURATION);
30+
replay['_loadAndCheckSession']();
3231
replay['_isEnabled'] = true;
3332
replay.eventBuffer = createEventBuffer({
3433
useCompression: options?.useCompression || false,

0 commit comments

Comments
 (0)