perf: Avoid per-transaction Timer thread in SentryTracer (JAVA-596) (#5670)
* perf: Avoid per-transaction Timer thread in SentryTracer (JAVA-570) Transactions with an idle or deadline timeout each created a java.util.Timer, which spawns a thread synchronously on the calling thread (often the main thread on Android). At scale (screen loads, HTTP spans) this was the dominant source of SDK thread churn. Schedule the idle/deadline timeouts on a dedicated, shared ISentryExecutorService held by SentryOptions instead, so no thread is created per transaction. It is kept separate from the main executor so timeout callbacks (which finish transactions) don't contend with cached event sending, and it is not prewarmed: its single worker thread is spawned lazily on the first scheduled timeout and reused thereafter. The dedicated executor uses removeOnCancelPolicy so cancelled timeouts (idle timers are rescheduled per child span) don't accumulate in its queue. On finish only the scheduled futures are cancelled; the executor is closed with the SDK. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * changelog * fix(core): Keep timer executor alive across SDK restart (JAVA-570) The shared timer executor introduced for transaction idle/deadline timeouts was shut down on every Scopes.close(), including SDK restart. This cancelled the pending idle timeout of any transaction started before the restart (e.g. an in-flight activity transaction), so it never auto-finished and its envelope was never sent. Only close the timer executor on a full close, not on restart, matching the pre-existing per-transaction Timer behaviour. Enable core-thread timeout on the timer executor so the instance abandoned by a restart self-terminates once idle instead of leaking a thread. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * refactor(core): Look up shared timer executor on demand (JAVA-570) SentryTracer cached the shared timer executor in a field for the lifetime of the transaction. Replace that field with a boolean flag tracking whether timeouts may still be scheduled, and fetch the executor from the options each time one is scheduled. This ensures the tracer always uses the executor currently held by the options (e.g. the fresh one installed after an SDK restart) rather than a stale reference. Also make the timer executor's keep-alive duration a constructor argument backed by the named TIMER_KEEP_ALIVE_SECONDS constant, and raise it from 10s to 30s so the shared worker thread is less likely to be torn down and respawned between transactions under normal use. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
N
Nelson Osacky committed
bcd3e76a8033a30cf291fc84c726d40205b21db2
Parent: dd1eb0c
Committed by GitHub <noreply@github.com>
on 7/15/2026, 9:16:35 AM