Skip to content

Commit d3674fe

Browse files
committed
fix: break circular reference when serializing Trace
1 parent da96122 commit d3674fe

File tree

1 file changed

+39
-32
lines changed

1 file changed

+39
-32
lines changed

src/v3/Trace.ts

Lines changed: 39 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ export class TraceStateMachine<
172172
VariantsT
173173
>,
174174
) {
175-
this.context = context
175+
this.#context = context
176176
this.remainingRequiredSpanIndexes = new Set(
177177
context.definition.requiredSpans.map((_, i) => i),
178178
)
@@ -181,13 +181,13 @@ export class TraceStateMachine<
181181

182182
readonly remainingRequiredSpanIndexes: Set<number>
183183

184-
readonly context: StateMachineContext<
184+
readonly #context: StateMachineContext<
185185
SelectedRelationNameT,
186186
RelationSchemasT,
187187
VariantsT
188188
>
189189
get sideEffectFns() {
190-
return this.context.sideEffectFns
190+
return this.#context.sideEffectFns
191191
}
192192
currentState: TraceStates = INITIAL_STATE
193193
/** the span that ended at the furthest point in time */
@@ -282,8 +282,8 @@ export class TraceStateMachine<
282282
draft: {
283283
onEnterState: () => {
284284
this.setGlobalDeadline(
285-
this.context.input.startTime.epoch +
286-
this.context.definition.variants[this.context.input.variant]!
285+
this.#context.input.startTime.epoch +
286+
this.#context.definition.variants[this.#context.input.variant]!
287287
.timeout,
288288
)
289289
},
@@ -312,10 +312,10 @@ export class TraceStateMachine<
312312

313313
// if the entry matches any of the interruptOnSpans criteria,
314314
// transition to complete state with the 'matched-on-interrupt' interruptionReason
315-
if (this.context.definition.interruptOnSpans) {
316-
for (const doesSpanMatch of this.context.definition
315+
if (this.#context.definition.interruptOnSpans) {
316+
for (const doesSpanMatch of this.#context.definition
317317
.interruptOnSpans) {
318-
if (doesSpanMatch(spanAndAnnotation, this.context)) {
318+
if (doesSpanMatch(spanAndAnnotation, this.#context)) {
319319
return {
320320
transitionToState: 'complete',
321321
interruptionReason: doesSpanMatch.requiredSpan
@@ -377,10 +377,10 @@ export class TraceStateMachine<
377377
}
378378

379379
// does span satisfy any of the "interruptOnSpans" definitions
380-
if (this.context.definition.interruptOnSpans) {
381-
for (const doesSpanMatch of this.context.definition
380+
if (this.#context.definition.interruptOnSpans) {
381+
for (const doesSpanMatch of this.#context.definition
382382
.interruptOnSpans) {
383-
if (doesSpanMatch(spanAndAnnotation, this.context)) {
383+
if (doesSpanMatch(spanAndAnnotation, this.#context)) {
384384
return {
385385
transitionToState: 'interrupted',
386386
interruptionReason: doesSpanMatch.requiredSpan
@@ -391,15 +391,19 @@ export class TraceStateMachine<
391391
}
392392
}
393393

394-
for (let i = 0; i < this.context.definition.requiredSpans.length; i++) {
394+
for (
395+
let i = 0;
396+
i < this.#context.definition.requiredSpans.length;
397+
i++
398+
) {
395399
if (!this.remainingRequiredSpanIndexes.has(i)) {
396400
// we previously checked off this index
397401
// eslint-disable-next-line no-continue
398402
continue
399403
}
400404

401-
const doesSpanMatch = this.context.definition.requiredSpans[i]!
402-
if (doesSpanMatch(spanAndAnnotation, this.context)) {
405+
const doesSpanMatch = this.#context.definition.requiredSpans[i]!
406+
if (doesSpanMatch(spanAndAnnotation, this.#context)) {
403407
// remove the index of this definition from the list of requiredSpans
404408
this.remainingRequiredSpanIndexes.delete(i)
405409

@@ -459,15 +463,15 @@ export class TraceStateMachine<
459463
this.lastRequiredSpan = this.lastRelevant
460464
this.lastRequiredSpan.annotation.markedRequirementsMet = true
461465

462-
if (!this.context.definition.debounceOnSpans) {
466+
if (!this.#context.definition.debounceOnSpans) {
463467
return { transitionToState: 'waiting-for-interactive' }
464468
}
465469
// set the first debounce deadline
466470
this.setDeadline(
467471
'debounce',
468472
this.lastRelevant.span.startTime.epoch +
469473
this.lastRelevant.span.duration +
470-
(this.context.definition.debounceWindow ??
474+
(this.#context.definition.debounceWindow ??
471475
DEFAULT_DEBOUNCE_DURATION),
472476
)
473477

@@ -528,9 +532,9 @@ export class TraceStateMachine<
528532
span: { ...span, isIdle: true },
529533
}
530534
if (idleRegressionCheckSpan) {
531-
for (const doesSpanMatch of this.context.definition.requiredSpans) {
535+
for (const doesSpanMatch of this.#context.definition.requiredSpans) {
532536
if (
533-
doesSpanMatch(idleRegressionCheckSpan, this.context) &&
537+
doesSpanMatch(idleRegressionCheckSpan, this.#context) &&
534538
doesSpanMatch.idleCheck
535539
) {
536540
// check if we regressed on "isIdle", and if so, transition to interrupted with reason
@@ -545,9 +549,10 @@ export class TraceStateMachine<
545549
this.sideEffectFns.addSpanToRecording(spanAndAnnotation)
546550

547551
// does span satisfy any of the "debouncedOn" and if so, restart our debounce timer
548-
if (this.context.definition.debounceOnSpans) {
549-
for (const doesSpanMatch of this.context.definition.debounceOnSpans) {
550-
if (doesSpanMatch(spanAndAnnotation, this.context)) {
552+
if (this.#context.definition.debounceOnSpans) {
553+
for (const doesSpanMatch of this.#context.definition
554+
.debounceOnSpans) {
555+
if (doesSpanMatch(spanAndAnnotation, this.#context)) {
551556
// Sometimes spans are processed out of order, we update the lastRelevant if this span ends later
552557
if (
553558
spanAndAnnotation.annotation.operationRelativeEndTime >
@@ -561,7 +566,7 @@ export class TraceStateMachine<
561566
'debounce',
562567
this.lastRelevant.span.startTime.epoch +
563568
this.lastRelevant.span.duration +
564-
(this.context.definition.debounceWindow ??
569+
(this.#context.definition.debounceWindow ??
565570
DEFAULT_DEBOUNCE_DURATION),
566571
)
567572
}
@@ -590,7 +595,7 @@ export class TraceStateMachine<
590595
}
591596

592597
this.completeSpan = this.lastRelevant
593-
const interactiveConfig = this.context.definition.captureInteractive
598+
const interactiveConfig = this.#context.definition.captureInteractive
594599
if (!interactiveConfig) {
595600
// nothing to do in this state, move to 'complete'
596601
return {
@@ -766,10 +771,10 @@ export class TraceStateMachine<
766771

767772
// if the entry matches any of the interruptOnSpans criteria,
768773
// transition to complete state with the 'matched-on-interrupt' interruptionReason
769-
if (this.context.definition.interruptOnSpans) {
770-
for (const doesSpanMatch of this.context.definition
774+
if (this.#context.definition.interruptOnSpans) {
775+
for (const doesSpanMatch of this.#context.definition
771776
.interruptOnSpans) {
772-
if (doesSpanMatch(spanAndAnnotation, this.context)) {
777+
if (doesSpanMatch(spanAndAnnotation, this.#context)) {
773778
return {
774779
transitionToState: 'complete',
775780
interruptionReason: doesSpanMatch.requiredSpan
@@ -1147,13 +1152,15 @@ export class Trace<
11471152
definition: this.definition,
11481153
// only keep items captured until the endOfOperationSpan
11491154
recordedItems: endOfOperationSpan
1150-
? [...this.recordedItems].filter(
1151-
(item) =>
1152-
item.span.startTime.now + item.span.duration <=
1153-
endOfOperationSpan.span.startTime.now +
1154-
endOfOperationSpan.span.duration,
1155+
? new Set(
1156+
[...this.recordedItems].filter(
1157+
(item) =>
1158+
item.span.startTime.now + item.span.duration <=
1159+
endOfOperationSpan.span.startTime.now +
1160+
endOfOperationSpan.span.duration,
1161+
),
11551162
)
1156-
: [...this.recordedItems],
1163+
: this.recordedItems,
11571164
input: this.input,
11581165
recordedItemsByLabel: this.recordedItemsByLabel,
11591166
},

0 commit comments

Comments
 (0)