-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(replay): Ignore old events when manually starting replay (#12349)
This PR ensures that if a replay is manually started (=no sample rates are defined at all, and a user later calls `start()` or `startBuffering()`, we do not back-port the `initialTimestamp` of the replay based on the event buffer. By default (for the first segment) we'll backport the `initialTimestamp` to the time of the first event in the event buffer, to ensure that e.g. the pageload browser metrics that may be emitted with an earlier timestamp all show up correctly. However, this may be unexpected if manually calling `startBuffering()` and seeing things for stuff that happened before. Now, we keep track of this and adjust the behavior accordingly. Fixes #11984 --------- Co-authored-by: Catherine Lee <55311782+c298lee@users.noreply.github.com>
- Loading branch information
Showing
2 changed files
with
119 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
107 changes: 107 additions & 0 deletions
107
packages/replay-internal/test/integration/earlyEvents.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
import { BASE_TIMESTAMP } from '..'; | ||
import { resetSdkMock } from '../mocks/resetSdkMock'; | ||
import { useFakeTimers } from '../utils/use-fake-timers'; | ||
|
||
useFakeTimers(); | ||
|
||
describe('Integration | early events', () => { | ||
beforeEach(() => { | ||
vi.clearAllMocks(); | ||
}); | ||
|
||
it('updates initialTimestamp for early performance entries', async () => { | ||
const earlyTimeStampSeconds = BASE_TIMESTAMP / 1000 - 10; | ||
|
||
const { replay } = await resetSdkMock({ | ||
replayOptions: { | ||
stickySession: true, | ||
}, | ||
sentryOptions: { | ||
replaysSessionSampleRate: 0, | ||
replaysOnErrorSampleRate: 1.0, | ||
}, | ||
}); | ||
|
||
expect(replay.session).toBeDefined(); | ||
expect(replay['_requiresManualStart']).toBe(false); | ||
|
||
const initialTimestamp = replay.getContext().initialTimestamp; | ||
|
||
expect(initialTimestamp).not.toEqual(earlyTimeStampSeconds * 1000); | ||
|
||
// A performance entry that happend before should not extend the session when we manually started | ||
replay.replayPerformanceEntries.push({ | ||
type: 'largest-contentful-paint', | ||
name: 'largest-contentful-paint', | ||
start: earlyTimeStampSeconds, | ||
end: earlyTimeStampSeconds, | ||
data: { | ||
value: 100, | ||
size: 100, | ||
nodeId: undefined, | ||
}, | ||
}); | ||
|
||
// _too_ early events are always thrown away | ||
replay.replayPerformanceEntries.push({ | ||
type: 'largest-contentful-paint', | ||
name: 'largest-contentful-paint', | ||
start: earlyTimeStampSeconds - 999999, | ||
end: earlyTimeStampSeconds - 99999, | ||
data: { | ||
value: 100, | ||
size: 100, | ||
nodeId: undefined, | ||
}, | ||
}); | ||
|
||
await replay.flushImmediate(); | ||
vi.runAllTimers(); | ||
|
||
expect(replay.getContext().initialTimestamp).toEqual(earlyTimeStampSeconds * 1000); | ||
}); | ||
|
||
it('does not change initialTimestamp when replay is manually started', async () => { | ||
const earlyTimeStampSeconds = Date.now() / 1000 - 5; | ||
|
||
const { replay } = await resetSdkMock({ | ||
replayOptions: { | ||
stickySession: true, | ||
}, | ||
sentryOptions: { | ||
replaysSessionSampleRate: 0.0, | ||
replaysOnErrorSampleRate: 0.0, | ||
}, | ||
}); | ||
|
||
expect(replay.session).toBe(undefined); | ||
expect(replay['_requiresManualStart']).toBe(true); | ||
|
||
replay.start(); | ||
vi.runAllTimers(); | ||
|
||
const initialTimestamp = replay.getContext().initialTimestamp; | ||
|
||
expect(initialTimestamp).not.toEqual(earlyTimeStampSeconds * 1000); | ||
expect(replay.session).toBeDefined(); | ||
expect(replay['_requiresManualStart']).toBe(true); | ||
|
||
// A performance entry that happened before should not extend the session when we manually started | ||
replay.replayPerformanceEntries.push({ | ||
type: 'largest-contentful-paint', | ||
name: 'largest-contentful-paint', | ||
start: earlyTimeStampSeconds, | ||
end: earlyTimeStampSeconds, | ||
data: { | ||
value: 100, | ||
size: 100, | ||
nodeId: undefined, | ||
}, | ||
}); | ||
|
||
await replay.flushImmediate(); | ||
vi.runAllTimers(); | ||
|
||
expect(replay.getContext().initialTimestamp).toEqual(initialTimestamp); | ||
}); | ||
}); |