Skip to content

perf: Drop pending timer tasks on shutdown to unblock close (JAVA-653) - #5851

Open
runningcode wants to merge 2 commits into
mainfrom
no/perf/timer-executor-shutdown-policy
Open

perf: Drop pending timer tasks on shutdown to unblock close (JAVA-653)#5851
runningcode wants to merge 2 commits into
mainfrom
no/perf/timer-executor-shutdown-policy

Conversation

@runningcode

@runningcode runningcode commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

This is a follow up on this comment: https://github.com/getsentry/sentry-java/pull/5814/changes#r3667006204

The timer executor is shut down in Scopes.close() via shutdown() followed by awaitTermination(shutdownTimeoutMillis). ScheduledThreadPoolExecutor keeps queued delayed tasks across shutdown() by default, so awaitTermination blocks for the full shutdown timeout (2s by default) whenever a long timeout is still pending at close time:

  • an unfinished transaction's idle/deadline timer (SentryTracer)
  • the 30s LifecycleWatcher end-session task, only cancelled on foregrounding
  • a rate limit lifted notification (RateLimiter, up to retry_after)

Setting executeExistingDelayedTasksAfterShutdownPolicy(false) drops those tasks at shutdown() instead. This is behaviour preserving: today they are discarded by the subsequent shutdownNow() once the timeout expires anyway, so the only thing lost is the wait.

The policy only affects shutdown(), so the SDK restart path that intentionally leaves the timer executor running (Scopes.close(isRestarting = true)) is unaffected. Scoped to the timer executor's constructor — the general-purpose executor keeps the default.

Measured with a standalone repro using the same executor configuration, one pending 60s task and a 2s timeout:

terminated blocked
before false 2000ms
after true 0ms

🤖 Generated with Claude Code

@linear-code

linear-code Bot commented Jul 29, 2026

Copy link
Copy Markdown

JAVA-653

@sentry

sentry Bot commented Jul 29, 2026

Copy link
Copy Markdown

📲 Install Builds

Android

🔗 App Name App ID Version Configuration
SDK Size io.sentry.tests.size 8.51.0 (1) release

⚙️ sentry-android Build Distribution Settings

@github-actions

github-actions Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Performance metrics 🚀

  Plain With Sentry Diff
Startup time 346.14 ms 420.32 ms 74.18 ms
Size 0 B 0 B 0 B

Baseline results on branch: main

Startup times

Revision Plain With Sentry Diff
d15471f 369.38 ms 459.08 ms 89.70 ms
bbc35bb 324.88 ms 425.73 ms 100.85 ms
b193867 319.59 ms 403.09 ms 83.50 ms
62b579c 299.75 ms 364.84 ms 65.09 ms
382d6c1 306.85 ms 368.70 ms 61.85 ms
48277cd 320.38 ms 379.90 ms 59.52 ms
5b1a06b 315.40 ms 353.33 ms 37.94 ms
ee747ae 415.92 ms 470.15 ms 54.23 ms
37ec571 366.04 ms 424.28 ms 58.23 ms
462dea2 277.68 ms 359.83 ms 82.15 ms

App size

Revision Plain With Sentry Diff
d15471f 1.58 MiB 2.13 MiB 559.54 KiB
bbc35bb 1.58 MiB 2.12 MiB 553.01 KiB
b193867 1.58 MiB 2.19 MiB 620.00 KiB
62b579c 0 B 0 B 0 B
382d6c1 1.58 MiB 2.29 MiB 719.85 KiB
48277cd 0 B 0 B 0 B
5b1a06b 0 B 0 B 0 B
ee747ae 1.58 MiB 2.10 MiB 530.95 KiB
37ec571 0 B 0 B 0 B
462dea2 0 B 0 B 0 B

Previous results on branch: no/perf/timer-executor-shutdown-policy

Startup times

Revision Plain With Sentry Diff
67051c0 411.49 ms 476.82 ms 65.33 ms

App size

Revision Plain With Sentry Diff
67051c0 0 B 0 B 0 B

}

@Test
fun `SentryExecutorService discards pending delayed tasks on shutdown when requested`() {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure we really need these tests.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the inline comment is enough to prevent regressions, so my vote would be to remove...

@runningcode runningcode added the sanity-check PR needs a lightweight review for obvious issues label Jul 29, 2026

@0xadam-brown 0xadam-brown left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice!

Does it make sense to apply the same policy to other / all of our Sentry executor services? (Doesn't have to stop us from merging this PR)

Comment thread sentry/src/main/java/io/sentry/SentryExecutorService.java
}

@Test
fun `SentryExecutorService discards pending delayed tasks on shutdown when requested`() {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the inline comment is enough to prevent regressions, so my vote would be to remove...

runningcode and others added 2 commits August 4, 2026 16:40
The timer executor is shut down by Scopes.close() via shutdown() followed
by awaitTermination(). ScheduledThreadPoolExecutor keeps queued delayed
tasks across shutdown() by default, so awaitTermination() blocks for the
full shutdown timeout (2s by default) whenever a long timeout is still
pending: an unfinished transaction's idle/deadline timer, the 30s
LifecycleWatcher end-session task, or a rate limit lifted notification.

Those tasks are discarded by the subsequent shutdownNow() anyway, so
dropping them upfront is behaviour preserving and only saves the wait.
This only affects shutdown(), so the SDK restart path that intentionally
leaves the timer executor running is unaffected.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@runningcode
runningcode force-pushed the no/perf/timer-executor-shutdown-policy branch from c9c256e to 08e41f2 Compare August 4, 2026 14:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

sanity-check PR needs a lightweight review for obvious issues

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants