Skip to content

Commit b9d5394

Browse files
authored
Merge pull request #33 from zendesk/ej/fix-interrupting-spans-capture
Fix interrupting spans capture
2 parents 8754e6a + 25392be commit b9d5394

File tree

2 files changed

+22
-19
lines changed

2 files changed

+22
-19
lines changed

src/v3/Trace.ts

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -265,14 +265,14 @@ export class TraceStateMachine<
265265
* if we have long tasks before FMP, we want to use them as a potential grouping post FMP.
266266
*/
267267
debouncingSpanBuffer: SpanAndAnnotation<RelationSchemasT>[] = []
268-
#provisionalBuffer: SpanAndAnnotation<RelationSchemasT>[] = []
268+
#draftBuffer: SpanAndAnnotation<RelationSchemasT>[] = []
269269

270270
// eslint-disable-next-line consistent-return
271-
#processProvisionalBuffer(): Transition<RelationSchemasT> | void {
271+
#processDraftBuffer(): Transition<RelationSchemasT> | void {
272272
// process items in the buffer (stick the relatedTo in the entries) (if its empty, well we can skip this!)
273273
let span: SpanAndAnnotation<RelationSchemasT> | undefined
274274
// eslint-disable-next-line no-cond-assign
275-
while ((span = this.#provisionalBuffer.shift())) {
275+
while ((span = this.#draftBuffer.shift())) {
276276
const transition = this.emit('onProcessSpan', span)
277277
if (transition) return transition
278278
}
@@ -316,6 +316,7 @@ export class TraceStateMachine<
316316
for (const doesSpanMatch of this.#context.definition
317317
.interruptOnSpans) {
318318
if (doesSpanMatch(spanAndAnnotation, this.#context)) {
319+
// TODO: do we want to record this span? Nothing else is being recorded at this point and is instead going into the buffer
319320
return {
320321
transitionToState: 'complete',
321322
interruptionReason: doesSpanMatch.requiredSpan
@@ -329,7 +330,7 @@ export class TraceStateMachine<
329330
}
330331

331332
// else, add into span buffer
332-
this.#provisionalBuffer.push(spanAndAnnotation)
333+
this.#draftBuffer.push(spanAndAnnotation)
333334
return undefined
334335
},
335336

@@ -352,7 +353,7 @@ export class TraceStateMachine<
352353

353354
active: {
354355
onEnterState: (_transition: OnEnterActive) => {
355-
const nextTransition = this.#processProvisionalBuffer()
356+
const nextTransition = this.#processDraftBuffer()
356357
if (nextTransition) return nextTransition
357358

358359
return undefined
@@ -381,6 +382,8 @@ export class TraceStateMachine<
381382
for (const doesSpanMatch of this.#context.definition
382383
.interruptOnSpans) {
383384
if (doesSpanMatch(spanAndAnnotation, this.#context)) {
385+
// still record the span that interrupted the trace
386+
this.sideEffectFns.addSpanToRecording(spanAndAnnotation)
384387
return {
385388
transitionToState: 'interrupted',
386389
interruptionReason: doesSpanMatch.requiredSpan
@@ -509,11 +512,13 @@ export class TraceStateMachine<
509512
}
510513
}
511514

515+
// The debouncing buffer will be used to correctly group the spans into clusters when calculating the cpu idle in the waiting-for-interactive state
516+
// We record the spans here as well, so that they are included even if we never make it out of the debouncing state
512517
this.debouncingSpanBuffer.push(spanAndAnnotation)
518+
this.sideEffectFns.addSpanToRecording(spanAndAnnotation)
513519

514520
if (spanEndTimeEpoch > this.#debounceDeadline) {
515521
// done debouncing
516-
this.sideEffectFns.addSpanToRecording(spanAndAnnotation)
517522
return { transitionToState: 'waiting-for-interactive' }
518523
}
519524

@@ -544,8 +549,6 @@ export class TraceStateMachine<
544549
}
545550
}
546551

547-
this.sideEffectFns.addSpanToRecording(spanAndAnnotation)
548-
549552
// does span satisfy any of the "debouncedOn" and if so, restart our debounce timer
550553
if (this.#context.definition.debounceOnSpans) {
551554
for (const doesSpanMatch of this.#context.definition
@@ -807,14 +810,14 @@ export class TraceStateMachine<
807810
// terminal states:
808811
interrupted: {
809812
onEnterState: (transition: OnEnterInterrupted) => {
810-
// depending on the reason, if we're coming from draft, we want to flush the provisional buffer:
813+
// depending on the reason, if we're coming from draft, we want to flush the buffer:
811814
if (
812815
transition.transitionFromState === 'draft' &&
813816
!isInvalidTraceInterruptionReason(transition.interruptionReason)
814817
) {
815818
let span: SpanAndAnnotation<RelationSchemasT> | undefined
816819
// eslint-disable-next-line no-cond-assign
817-
while ((span = this.#provisionalBuffer.shift())) {
820+
while ((span = this.#draftBuffer.shift())) {
818821
this.sideEffectFns.addSpanToRecording(span)
819822
}
820823
}

src/v3/TraceManager.test.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -472,9 +472,9 @@ describe('TraceManager', () => {
472472
(spanAndAnnotation) => spanAndAnnotation.span.performanceEntry,
473473
),
474474
).toMatchInlineSnapshot(`
475-
events | start
476-
timeline | |
477-
time (ms) | 0
475+
events | start interrupt
476+
timeline | |-<⋯ +100 ⋯>-|
477+
time (ms) | 0 100
478478
`)
479479
expect(report.name).toBe('ticket.interrupt-on-basic-operation')
480480
expect(report.duration).toBeNull()
@@ -554,8 +554,8 @@ describe('TraceManager', () => {
554554
name: 'ticket.interrupt-on-basic-operation',
555555
type: 'operation',
556556
relationSchemaName: 'ticket',
557-
requiredSpans: [{ name: 'end', isIdle: true }],
558-
debounceOnSpans: [{ name: 'end' }],
557+
requiredSpans: [{ name: 'component', isIdle: true }],
558+
debounceOnSpans: [{ name: 'component' }],
559559
variants: {
560560
cold_boot: { timeout: DEFAULT_COLDBOOT_TIMEOUT_DURATION },
561561
},
@@ -569,7 +569,7 @@ describe('TraceManager', () => {
569569

570570
// prettier-ignore
571571
const { spans } = getSpansFromTimeline<TicketIdRelationSchemasFixture>`
572-
Events: ${Render('start', 0)}-----${Render('end', 50, {isIdle: true})}-----${Render('end', 50, {isIdle: false})}
572+
Events: ${Render('start', 0)}-----${Render('component', 50, {isIdle: true})}-----${Render('component', 50, {isIdle: false})}
573573
Time: ${0} ${100} ${200}
574574
`
575575

@@ -585,9 +585,9 @@ describe('TraceManager', () => {
585585
(spanAndAnnotation) => spanAndAnnotation.span.performanceEntry,
586586
),
587587
).toMatchInlineSnapshot(`
588-
events | start end(50)
589-
timeline | |-<⋯ +100 ⋯>-[++++++++++++++++++++++++++++++++++++++++++++++++]
590-
time (ms) | 0 100
588+
events | start component(50) component(50)
589+
timeline | |-<⋯ +100 ⋯>-[++++++++++++++]---------------[++++++++++++++]-
590+
time (ms) | 0 100 200
591591
`)
592592
expect(report.name).toBe('ticket.interrupt-on-basic-operation')
593593
expect(report.interruptionReason).toBe('idle-component-no-longer-idle')

0 commit comments

Comments
 (0)