Skip to content

Commit

Permalink
fix(replay): Fix user activity not being updated in start() (#12001)
Browse files Browse the repository at this point in the history
Replays will fail to start recording when using `start()` specifically
when manually recording and after the user has been idle for a long
period of time. We need to reset the user activity state when we call
`start()`, otherwise the session will be [incorrectly] considered to be
idle and unable to send any replay events.

Closes #11983
  • Loading branch information
billyvg authored May 13, 2024
1 parent 9510771 commit 945c19e
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 0 deletions.
7 changes: 7 additions & 0 deletions packages/replay-internal/src/replay.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import { clearSession } from './session/clearSession';
import { loadOrCreateSession } from './session/loadOrCreateSession';
import { saveSession } from './session/saveSession';
import { shouldRefreshSession } from './session/shouldRefreshSession';

import type {
AddEventResult,
AddUpdateCallback,
Expand Down Expand Up @@ -295,6 +296,12 @@ export class ReplayContainer implements ReplayContainerInterface {

logInfoNextTick('[Replay] Starting replay in session mode', this._options._experiments.traceInternals);

// Required as user activity is initially set in
// constructor, so if `start()` is called after
// session idle expiration, a replay will not be
// created due to an idle timeout.
this._updateUserActivity();

const session = loadOrCreateSession(
{
maxReplayDuration: this._options.maxReplayDuration,
Expand Down
52 changes: 52 additions & 0 deletions packages/replay-internal/test/integration/start.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { vi } from 'vitest';

import { getClient } from '@sentry/core';
import type { Transport } from '@sentry/types';

import { DEFAULT_FLUSH_MIN_DELAY, SESSION_IDLE_EXPIRE_DURATION } from '../../src/constants';
import type { Replay } from '../../src/integration';
import type { ReplayContainer } from '../../src/replay';
import { BASE_TIMESTAMP } from '../index';
import { resetSdkMock } from '../mocks/resetSdkMock';
import { useFakeTimers } from '../utils/use-fake-timers';

useFakeTimers();

describe('Integration | start', () => {
let replay: ReplayContainer;
let integration: Replay;

beforeEach(async () => {
({ replay, integration } = await resetSdkMock({
replayOptions: {
stickySession: false,
},
sentryOptions: {
replaysSessionSampleRate: 0.0,
},
}));

const mockTransport = getClient()?.getTransport()?.send as vi.MockedFunction<Transport['send']>;
mockTransport?.mockClear();
await vi.runAllTimersAsync();
});

afterEach(async () => {
integration.stop();

await vi.runAllTimersAsync();
vi.setSystemTime(new Date(BASE_TIMESTAMP));
});

it('sends replay when calling `start()` after [SESSION_IDLE_EXPIRE_DURATION]ms', async () => {
await vi.advanceTimersByTimeAsync(SESSION_IDLE_EXPIRE_DURATION + 1);

integration.start();

await vi.advanceTimersByTimeAsync(DEFAULT_FLUSH_MIN_DELAY);

expect(replay).toHaveLastSentReplay({
recordingPayloadHeader: { segment_id: 0 },
});
});
});

0 comments on commit 945c19e

Please sign in to comment.