Skip to content

Commit 5debdf7

Browse files
authored
feat: No longer debounce IdleTransaction (#2618)
* feat: No longer debounce IdleTransaction * chore: Changelog * fix: Slight wording change
1 parent 5e0bc0a commit 5debdf7

File tree

2 files changed

+27
-16
lines changed

2 files changed

+27
-16
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
- [apm] feat: Introduce `Sentry.startTransaction` and `Transaction.startChild` #2600
2020
- [apm] feat: Transactions no longer go through `beforeSend` #2600
2121
- [browser] fix: Emit Sentry Request breadcrumbs from inside the client (#2615)
22+
- [apm] fix: No longer debounce IdleTransaction #2618
2223

2324
## 5.15.5
2425

packages/apm/src/integrations/tracing.ts

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
logger,
88
safeJoin,
99
supportsNativeFetch,
10+
timestampWithMs,
1011
} from '@sentry/utils';
1112

1213
import { Span as SpanClass } from '../span';
@@ -60,10 +61,8 @@ interface TracingOptions {
6061
startTransactionOnLocationChange: boolean;
6162

6263
/**
63-
* The maximum duration of a transaction before it will be discarded. This is for some edge cases where a browser
64-
* completely freezes the JS state and picks it up later (background tabs).
65-
* So after this duration, the SDK will not send the event.
66-
* If you want to have an unlimited duration set it to 0.
64+
* The maximum duration of a transaction before it will be marked as "deadline_exceeded".
65+
* If you never want to mark a transaction set it to 0.
6766
* Time is in seconds.
6867
*
6968
* Default: 600
@@ -138,7 +137,7 @@ export class Tracing implements Integration {
138137

139138
public static _activities: { [key: number]: Activity } = {};
140139

141-
private static _debounce: number = 0;
140+
private static _idleTransactionEndTimestamp: number = 0;
142141

143142
private readonly _emitOptionsWarning: boolean = false;
144143

@@ -419,7 +418,7 @@ export class Tracing implements Integration {
419418
// b) A activity wasn't popped correctly and therefore the transaction is stalling
420419
Tracing.finishIdleTransaction();
421420

422-
Tracing._log('[Tracing] startIdleTransaction, name:', transactionContext.name);
421+
Tracing._log('[Tracing] startIdleTransaction');
423422

424423
const _getCurrentHub = Tracing._getCurrentHub;
425424
if (!_getCurrentHub) {
@@ -453,7 +452,21 @@ export class Tracing implements Integration {
453452
const active = Tracing._activeTransaction;
454453
if (active) {
455454
Tracing._addPerformanceEntries(active);
456-
Tracing._log('[Tracing] finishIdleTransaction', active.name);
455+
Tracing._log('[Tracing] finishIdleTransaction');
456+
457+
if (active.spanRecorder) {
458+
const timeout = (Tracing.options && Tracing.options.idleTimeout) || 100;
459+
active.spanRecorder.spans = active.spanRecorder.spans.filter((finishedSpan: Span) => {
460+
const keepSpan = finishedSpan.startTimestamp < Tracing._idleTransactionEndTimestamp + timeout;
461+
if (!keepSpan) {
462+
Tracing._log(
463+
'[Tracing] discarding Span since it happened after Transaction was finished',
464+
finishedSpan.toJSON(),
465+
);
466+
}
467+
return keepSpan;
468+
});
469+
}
457470
active.finish();
458471
Tracing._resetActiveTransaction();
459472
}
@@ -477,7 +490,7 @@ export class Tracing implements Integration {
477490
const timeOrigin = Tracing._msToSec(performance.timeOrigin);
478491

479492
// tslint:disable-next-line: completed-docs
480-
function addPerformanceNavigationTiming(parent: SpanClass, entry: { [key: string]: number }, event: string): void {
493+
function addPerformanceNavigationTiming(parent: Span, entry: { [key: string]: number }, event: string): void {
481494
const span = parent.startChild({
482495
description: event,
483496
op: 'browser',
@@ -487,7 +500,7 @@ export class Tracing implements Integration {
487500
}
488501

489502
// tslint:disable-next-line: completed-docs
490-
function addRequest(parent: SpanClass, entry: { [key: string]: number }): void {
503+
function addRequest(parent: Span, entry: { [key: string]: number }): void {
491504
const request = parent.startChild({
492505
description: 'request',
493506
op: 'browser',
@@ -560,7 +573,7 @@ export class Tracing implements Integration {
560573
if (entry.initiatorType === 'xmlhttprequest' || entry.initiatorType === 'fetch') {
561574
// We need to update existing spans with new timing info
562575
if (transactionSpan.spanRecorder) {
563-
transactionSpan.spanRecorder.spans.map((finishedSpan: SpanClass) => {
576+
transactionSpan.spanRecorder.spans.map((finishedSpan: Span) => {
564577
if (finishedSpan.description && finishedSpan.description.indexOf(resourceName) !== -1) {
565578
finishedSpan.startTimestamp = timeOrigin + startTime;
566579
finishedSpan.endTimestamp = finishedSpan.startTimestamp + duration;
@@ -669,9 +682,6 @@ export class Tracing implements Integration {
669682
return 0;
670683
}
671684

672-
// We want to clear the timeout also here since we push a new activity
673-
clearTimeout(Tracing._debounce);
674-
675685
const _getCurrentHub = Tracing._getCurrentHub;
676686
if (spanContext && _getCurrentHub) {
677687
const hub = _getCurrentHub();
@@ -740,16 +750,16 @@ export class Tracing implements Integration {
740750
}
741751

742752
const count = Object.keys(Tracing._activities).length;
743-
clearTimeout(Tracing._debounce);
744753

745754
Tracing._log('[Tracing] activies count', count);
746755

747756
if (count === 0 && Tracing._activeTransaction) {
748757
const timeout = Tracing.options && Tracing.options.idleTimeout;
749758
Tracing._log(`[Tracing] Flushing Transaction in ${timeout}ms`);
750-
Tracing._debounce = (setTimeout(() => {
759+
Tracing._idleTransactionEndTimestamp = timestampWithMs();
760+
setTimeout(() => {
751761
Tracing.finishIdleTransaction();
752-
}, timeout) as any) as number;
762+
}, timeout);
753763
}
754764
}
755765
}

0 commit comments

Comments
 (0)