Skip to content

Commit 4c195df

Browse files
committed
feat(replay): Change addEvent to be async
`addEvent` should be async as it waits for a response from Compression worker.
1 parent dec280a commit 4c195df

File tree

8 files changed

+52
-31
lines changed

8 files changed

+52
-31
lines changed

packages/replay/src/eventBuffer.ts

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,9 @@
22
// TODO: figure out member access types and remove the line above
33

44
import { captureException } from '@sentry/core';
5-
import { ReplayRecordingData } from '@sentry/types';
65
import { logger } from '@sentry/utils';
76

8-
import type { EventBuffer, RecordingEvent, WorkerRequest, WorkerResponse } from './types';
7+
import type { EventBuffer, RecordingEvent, WorkerAddEventResponse,WorkerRequest, WorkerResponse } from './types';
98
import workerString from './worker/worker.js';
109

1110
interface CreateEventBufferParams {
@@ -54,13 +53,14 @@ class EventBufferArray implements EventBuffer {
5453
this._events = [];
5554
}
5655

57-
public addEvent(event: RecordingEvent, isCheckout?: boolean): void {
56+
public async addEvent(event: RecordingEvent, isCheckout?: boolean): Promise<boolean> {
5857
if (isCheckout) {
5958
this._events = [event];
60-
return;
59+
return true;
6160
}
6261

6362
this._events.push(event);
63+
return true
6464
}
6565

6666
public finish(): Promise<string> {
@@ -107,8 +107,10 @@ export class EventBufferCompressionWorker implements EventBuffer {
107107

108108
/**
109109
* Add an event to the event buffer.
110+
*
111+
* Returns true if event was successfuly received and processed by worker.
110112
*/
111-
public async addEvent(event: RecordingEvent, isCheckout?: boolean): Promise<ReplayRecordingData> {
113+
public async addEvent(event: RecordingEvent, isCheckout?: boolean): Promise<WorkerAddEventResponse> {
112114
if (isCheckout) {
113115
// This event is a checkout, make sure worker buffer is cleared before
114116
// proceeding.
@@ -178,17 +180,17 @@ export class EventBufferCompressionWorker implements EventBuffer {
178180
/**
179181
* Send the event to the worker.
180182
*/
181-
private _sendEventToWorker(event: RecordingEvent): Promise<ReplayRecordingData> {
183+
private async _sendEventToWorker(event: RecordingEvent): Promise<WorkerAddEventResponse> {
182184
const promise = this._postMessage({
183-
id: this._getAndIncrementId(),
185+
id: this._getAndIncrementId(),
184186
method: 'addEvent',
185187
args: [event],
186188
});
187189

188190
// XXX: See note in `get length()`
189191
this._eventBufferItemLength++;
190192

191-
return promise;
193+
return promise as Promise<WorkerAddEventResponse>;
192194
}
193195

194196
/**

packages/replay/src/replay.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import type {
3636
ReplayPluginOptions,
3737
SendReplay,
3838
Session,
39+
WorkerAddEventResponse,
3940
} from './types';
4041
import { addEvent } from './util/addEvent';
4142
import { addMemoryEntry } from './util/addMemoryEntry';
@@ -702,12 +703,12 @@ export class ReplayContainer implements ReplayContainerInterface {
702703
* Observed performance events are added to `this.performanceEvents`. These
703704
* are included in the replay event before it is finished and sent to Sentry.
704705
*/
705-
addPerformanceEntries(): void {
706+
addPerformanceEntries(): Promise<Array<WorkerAddEventResponse|null>> {
706707
// Copy and reset entries before processing
707708
const entries = [...this.performanceEvents];
708709
this.performanceEvents = [];
709710

710-
createPerformanceSpans(this, createPerformanceEntries(entries));
711+
return Promise.all(createPerformanceSpans(this, createPerformanceEntries(entries)));
711712
}
712713

713714
/**

packages/replay/src/types.ts

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,11 @@ export interface WorkerResponse {
4848
id: number;
4949
method: string;
5050
success: boolean;
51-
response: ReplayRecordingData;
51+
response: unknown;
5252
}
5353

54+
export type WorkerAddEventResponse = boolean;
55+
5456
export interface SampleRates {
5557
/**
5658
* The sample rate for session-long replays. 1.0 will record all sessions and
@@ -210,8 +212,22 @@ export interface Session {
210212

211213
export interface EventBuffer {
212214
readonly length: number;
215+
216+
/**
217+
* Destroy the event buffer.
218+
*/
213219
destroy(): void;
214-
addEvent(event: RecordingEvent, isCheckout?: boolean): void;
220+
221+
/**
222+
* Add an event to the event buffer.
223+
*
224+
* Returns true if event was successfully added.
225+
*/
226+
addEvent(event: RecordingEvent, isCheckout?: boolean): Promise<WorkerAddEventResponse>;
227+
228+
/**
229+
* Clears and returns the contents and the buffer.
230+
*/
215231
finish(): Promise<ReplayRecordingData>;
216232
}
217233

packages/replay/src/util/addEvent.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,19 @@
1+
12
import { SESSION_IDLE_DURATION } from '../constants';
2-
import type { RecordingEvent, ReplayContainer } from '../types';
3+
import type { RecordingEvent, ReplayContainer, WorkerAddEventResponse } from '../types';
34

45
/**
56
* Add an event to the event buffer
67
*/
7-
export function addEvent(replay: ReplayContainer, event: RecordingEvent, isCheckout?: boolean): void {
8+
export async function addEvent(replay: ReplayContainer, event: RecordingEvent, isCheckout?: boolean): Promise<WorkerAddEventResponse|null> {
89
if (!replay.eventBuffer) {
910
// This implies that `_isEnabled` is false
10-
return;
11+
return null;
1112
}
1213

1314
if (replay.isPaused()) {
1415
// Do not add to event buffer when recording is paused
15-
return;
16+
return null;
1617
}
1718

1819
// TODO: sadness -- we will want to normalize timestamps to be in ms -
@@ -25,7 +26,7 @@ export function addEvent(replay: ReplayContainer, event: RecordingEvent, isCheck
2526
// comes back to trigger a new session. The performance entries rely on
2627
// `performance.timeOrigin`, which is when the page first opened.
2728
if (timestampInMs + SESSION_IDLE_DURATION < new Date().getTime()) {
28-
return;
29+
return null;
2930
}
3031

3132
// Only record earliest event if a new session was created, otherwise it
@@ -35,5 +36,5 @@ export function addEvent(replay: ReplayContainer, event: RecordingEvent, isCheck
3536
replay.getContext().earliestEvent = timestampInMs;
3637
}
3738

38-
replay.eventBuffer.addEvent(event, isCheckout);
39+
return replay.eventBuffer.addEvent(event, isCheckout);
3940
}

packages/replay/src/util/addMemoryEntry.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { WINDOW } from '../constants';
2-
import type { ReplayContainer, ReplayPerformanceEntry } from '../types';
2+
import type { ReplayContainer, ReplayPerformanceEntry, WorkerAddEventResponse } from '../types';
33
import { createPerformanceSpans } from './createPerformanceSpans';
44

55
type ReplayMemoryEntry = ReplayPerformanceEntry & { data: { memory: MemoryInfo } };
@@ -14,15 +14,16 @@ interface MemoryInfo {
1414
* Create a "span" for the total amount of memory being used by JS objects
1515
* (including v8 internal objects).
1616
*/
17-
export function addMemoryEntry(replay: ReplayContainer): void {
17+
export async function addMemoryEntry(replay: ReplayContainer): Promise<Array<WorkerAddEventResponse|null>> {
1818
// window.performance.memory is a non-standard API and doesn't work on all browsers, so we try-catch this
1919
try {
20-
createPerformanceSpans(replay, [
20+
return Promise.all(createPerformanceSpans(replay, [
2121
// @ts-ignore memory doesn't exist on type Performance as the API is non-standard (we check that it exists above)
2222
createMemoryEntry(WINDOW.performance.memory),
23-
]);
23+
]));
2424
} catch (error) {
2525
// Do nothing
26+
return []
2627
}
2728
}
2829

packages/replay/src/util/createPerformanceSpans.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import { EventType } from 'rrweb';
22

3-
import type { ReplayContainer, ReplayPerformanceEntry } from '../types';
3+
import type { ReplayContainer, ReplayPerformanceEntry, WorkerAddEventResponse } from '../types';
44
import { addEvent } from './addEvent';
55

66
/**
77
* Create a "span" for each performance entry. The parent transaction is `this.replayEvent`.
88
*/
9-
export function createPerformanceSpans(replay: ReplayContainer, entries: ReplayPerformanceEntry[]): void {
10-
entries.map(({ type, start, end, name, data }) =>
9+
export function createPerformanceSpans(replay: ReplayContainer, entries: ReplayPerformanceEntry[]): Promise<WorkerAddEventResponse|null>[] {
10+
return entries.map(({ type, start, end, name, data }) =>
1111
addEvent(replay, {
1212
type: EventType.Custom,
1313
timestamp: start,

packages/replay/worker/src/Compressor.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,20 +25,21 @@ export class Compressor {
2525
return;
2626
}
2727

28-
public addEvent(data: Record<string, unknown>): void {
28+
public addEvent(data: Record<string, unknown>): boolean {
2929
if (!data) {
30-
return;
30+
return false;
3131
}
3232
// If the event is not the first event, we need to prefix it with a `,` so
3333
// that we end up with a list of events
3434
const prefix = this.added > 0 ? ',' : '';
3535
// TODO: We may want Z_SYNC_FLUSH or Z_FULL_FLUSH (not sure the difference)
3636
// Using NO_FLUSH here for now as we can create many attachments that our
3737
// web UI will get API rate limited.
38-
this.deflate.push(prefix + JSON.stringify(data), constants.Z_NO_FLUSH);
38+
this.deflate.push(prefix + JSON.stringify(data), constants.Z_SYNC_FLUSH);
39+
3940
this.added++;
4041

41-
return;
42+
return true;
4243
}
4344

4445
public finish(): Uint8Array {

packages/replay/worker/src/handleMessage.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,7 @@ const handlers: Handlers = {
1616
},
1717

1818
addEvent: (data: Record<string, unknown>) => {
19-
compressor.addEvent(data);
20-
return '';
19+
return compressor.addEvent(data);
2120
},
2221

2322
finish: () => {

0 commit comments

Comments
 (0)