Skip to content

Commit 2756060

Browse files
committed
feat(replay): Track pending events in EventBuffer
* Track raw pending events in `EventBuffer`. This can be helpful in the case where page is reloaded before the worker has a chance to close the compression stream. * Change `EventBuffer.length` to `EventBuffer.pendingLength` to better reflect what it is. In the case of compression worker, it is async, so recent events added to the buffer are not necessarily present in the workers compression stream.
1 parent 770a33d commit 2756060

File tree

4 files changed

+50
-10
lines changed

4 files changed

+50
-10
lines changed

packages/replay/src/eventBuffer.ts

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,18 @@ class EventBufferArray implements EventBuffer {
4545
this._events = [];
4646
}
4747

48-
public get length(): number {
48+
public get pendingLength(): number {
4949
return this._events.length;
5050
}
5151

52+
/**
53+
* Returns the raw events that are buffered. In `EventBufferArray`, this is the
54+
* same as `this._events`.
55+
*/
56+
public get pendingEvents(): RecordingEvent[] {
57+
return this._events;
58+
}
59+
5260
public destroy(): void {
5361
this._events = [];
5462
}
@@ -80,6 +88,13 @@ class EventBufferArray implements EventBuffer {
8088
* Exported only for testing.
8189
*/
8290
export class EventBufferCompressionWorker implements EventBuffer {
91+
/**
92+
* Keeps track of the list of events since the last flush that have not been compressed.
93+
* For example, page is reloaded and a flush attempt is made, but
94+
* `finish()` (and thus the flush), does not complete.
95+
*/
96+
public _pendingEvents: RecordingEvent[] = [];
97+
8398
private _worker: null | Worker;
8499
private _eventBufferItemLength: number = 0;
85100
private _id: number = 0;
@@ -89,13 +104,21 @@ export class EventBufferCompressionWorker implements EventBuffer {
89104
}
90105

91106
/**
92-
* Note that this may not reflect what is actually in the event buffer. This
93-
* is only a local count of the buffer size since `addEvent` is async.
107+
* The number of raw events that are buffered. This may not be the same as
108+
* the number of events that have been compresed in the worker because
109+
* `addEvent` is async.
94110
*/
95-
public get length(): number {
111+
public get pendingLength(): number {
96112
return this._eventBufferItemLength;
97113
}
98114

115+
/**
116+
* Returns a list of the raw recording events that are being compressed.
117+
*/
118+
public get pendingEvents(): RecordingEvent[] {
119+
return this._pendingEvents;
120+
}
121+
99122
/**
100123
* Destroy the event buffer.
101124
*/
@@ -121,6 +144,11 @@ export class EventBufferCompressionWorker implements EventBuffer {
121144
});
122145
}
123146

147+
// Don't store checkout events in `_pendingEvents` because they are too large
148+
if (!isCheckout) {
149+
this._pendingEvents.push(event);
150+
}
151+
124152
return this._sendEventToWorker(event);
125153
}
126154

@@ -202,6 +230,10 @@ export class EventBufferCompressionWorker implements EventBuffer {
202230
// XXX: See note in `get length()`
203231
this._eventBufferItemLength = 0;
204232

233+
await promise;
234+
235+
this._pendingEvents = [];
236+
205237
return promise;
206238
}
207239

packages/replay/src/replay.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -794,7 +794,7 @@ export class ReplayContainer implements ReplayContainerInterface {
794794

795795
await this.addPerformanceEntries();
796796

797-
if (!this.eventBuffer?.length) {
797+
if (!this.eventBuffer?.pendingLength) {
798798
return;
799799
}
800800

packages/replay/src/types.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,15 @@ export interface Session {
211211
}
212212

213213
export interface EventBuffer {
214-
readonly length: number;
214+
/**
215+
* The number of raw events that are buffered
216+
*/
217+
readonly pendingLength: number;
218+
219+
/**
220+
* The raw events that are buffered.
221+
*/
222+
readonly pendingEvents: RecordingEvent[];
215223

216224
/**
217225
* Destroy the event buffer.
@@ -226,7 +234,7 @@ export interface EventBuffer {
226234
addEvent(event: RecordingEvent, isCheckout?: boolean): Promise<AddEventResult>;
227235

228236
/**
229-
* Clears and returns the contents and the buffer.
237+
* Clears and returns the contents of the buffer.
230238
*/
231239
finish(): Promise<ReplayRecordingData>;
232240
}

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -128,17 +128,17 @@ describe('Integration | stop', () => {
128128

129129
it('does not buffer events when stopped', async function () {
130130
WINDOW.dispatchEvent(new Event('blur'));
131-
expect(replay.eventBuffer?.length).toBe(1);
131+
expect(replay.eventBuffer?.pendingLength).toBe(1);
132132

133133
// stop replays
134134
integration.stop();
135135

136-
expect(replay.eventBuffer?.length).toBe(undefined);
136+
expect(replay.eventBuffer?.pendingLength).toBe(undefined);
137137

138138
WINDOW.dispatchEvent(new Event('blur'));
139139
await new Promise(process.nextTick);
140140

141-
expect(replay.eventBuffer?.length).toBe(undefined);
141+
expect(replay.eventBuffer?.pendingLength).toBe(undefined);
142142
expect(replay).not.toHaveLastSentReplay();
143143
});
144144

0 commit comments

Comments
 (0)