-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(tracing): Reset IdleTimeout based on activities count #4531
Conversation
size-limit report
|
9e40065
to
8c35b6d
Compare
This branch tracks the beta for `6.17.8-beta.0`. For more information, see: #4531.
CHANGELOG for non-beta items: https://github.com/getsentry/sentry-javascript/blob/master/CHANGELOG.md https://github.com/getsentry/sentry-javascript/releases/tag/6.17.8-beta.0 See getsentry/sentry-javascript#4531 for changes we are testing
CHANGELOG for non-beta items: https://github.com/getsentry/sentry-javascript/blob/master/CHANGELOG.md https://github.com/getsentry/sentry-javascript/releases/tag/6.17.8-beta.0 See getsentry/sentry-javascript#4531 for changes we are testing
It's okay - I just lowered it 4%, so we're still ahead. 😛 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A few comments, but overall looks good! (I actually didn't realize we don't already do this.)
* Time is in ms. | ||
* | ||
* Default: 1000 | ||
*/ | ||
idleTimeout: number; | ||
|
||
/** | ||
* The max transaction duration for a transaction. If a transaction duration hits the `finalTimeout` value, it |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
* The max transaction duration for a transaction. If a transaction duration hits the `finalTimeout` value, it | |
* The max duration for a transaction. If a transaction duration hits the `finalTimeout` value, it |
@@ -96,11 +111,13 @@ export class IdleTransaction extends Transaction { | |||
_idleHub.configureScope(scope => scope.setSpan(this)); | |||
} | |||
|
|||
this._initTimeout = setTimeout(() => { | |||
this._startIdleTimeout(); | |||
global.setTimeout(() => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this need to be called on global
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It makes it less likely to fail in the future - so I set it this way.
/** | ||
* Creates an idletimeout | ||
*/ | ||
private _startIdleTimeout(end?: Parameters<IdleTransaction['finish']>[0]): void { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When using Parameters
, I think it's helpful to give the variable the same name as the parameter in question. (Also, renaming this makes it clearer what it actually is.)
private _startIdleTimeout(end?: Parameters<IdleTransaction['finish']>[0]): void { | |
private _startIdleTimeout(endTimestamp?: Parameters<IdleTransaction['finish']>[0]): void { |
this._idleTimeoutID = global.setTimeout(() => { | ||
if (!this._finished && Object.keys(this.activities).length === 0) { | ||
this.setTag(FINISH_REASON_TAG, IDLE_TRANSACTION_FINISH_REASONS[1]); | ||
this.finish(end); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this.finish(end); | |
this.finish(endTimestamp); |
this.finish(end); | ||
} | ||
}, timeout); | ||
this._startIdleTimeout(end); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this._startIdleTimeout(end); | |
this._startIdleTimeout(endTimestamp); |
(It won't let me fix the line above, because it hasn't been changed, but there, too.)
* Creates an idletimeout | ||
*/ | ||
private _startIdleTimeout(end?: Parameters<IdleTransaction['finish']>[0]): void { | ||
this._cancelIdleTimeout(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder what test covers the behaviour changes?
Does its 2 test cases will to it?
https://github.com/getsentry/sentry-javascript/pull/4442/files#diff-69402bcbb230fa3d9774ae3cc7f75cecc78e369775e6fa222ae406f1d4dcfef2R197-R230
'heartbeatFailed', | ||
'idleTimeout', | ||
'documentHidden', | ||
'finalTimeout', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
given that this shows up in the UI, and I as a user of sentry would probably not understand what this means if I hadn't already found this issue and read this PR, does it make more sense to name this something that indicates it's a forced timeout due to thrashing? hard to come up with a concise name but maybe something like thrashedSpanTimeout
or timeoutInfinitePoll
? (idleTimeout
was a similarly confusing name to me, it's not obvious that's the sort of "intended finish reason" for normal transactions, but realize that probably can't be changed anymore)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch.
Its behaviour seems like as the maxTransactionDuration
configuration.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
does it make sense to re-use that configuration option here then (as opposed to creating a new one), and similarly re-use the "deadline_exceeded" finishReason? or is there value in having them both be separate? I guess a default timeout of 600 seconds is pretty excessive for this particular use case...
@snoozbuster @alquerci thanks for the comments. We're running some tests off a beta on the Sentry frontend right now (getsentry/sentry#31761), and once we've got that data, I'll come back and formally reply to the review comments. We'll also share the data here - and give y'all an opportunity to give feedback. Appreciate the patience! |
This reverts commit e68a672.
Uhh that wasn't supposed to happen We are close to shipping this though. |
getsentry/sentry-javascript#4531 This will also fix the console array problem.
getsentry/sentry-javascript#4531 This will also fix the console array problem.
I can't locate these changes in master even though the PR says they've been merged. Is there another 6.x release I can use or should I go directly to 7.x for this? |
These changes are part of the latest |
I just switched to the 7.x branch and my staggered activities problems immediately disappeared. Thanks and great work! |
Previously, when the activities count of an idle transaction hit 0, it would trigger a timeout for
idleTimeout
ms, and then always end the transaction. This means that if a span (like fetch/xhr request) started right after the activities count went to 0 (1 -> 0 -> 1), the transaction would always finish afteridleTimeout
ms, instead of waiting for the newest activity to finish.This was primarily done to prevent polling conditions and to not artificially inflate duration. Nowadays though, web vitals like LCP are a lot more important as a measurement in transactions than the strict duration (as with activities, they are a bit arbitrary). By making
idleTimeout
be strict about finish after activities go to 0, we often times would miss the LCP value that the browser would record, leading to many transactions not having proper LCPs.To get the LCP value close to browser quality as possible, we now reset the
idleTimeout
timeout if there are still existing activities. The concern here is with polling. To prevent polling issues, we now also have an additionalfinalTimeout
that is started when the idle transaction is created. This double timeout system (alongside the heartbeat), should always enforce that the transaction is finished.To test out these new options, we are cutting a beta to test on getsentry/sentry first, and then we will think about how to do a full release with this.
An image explanation (opt-in)
Sorry for adding bytes tracing bundle 😢