Skip to content

perf: Share one executor between log and metrics batch processors (JAVA-653) - #5818

Draft
runningcode wants to merge 2 commits into
mainfrom
no/perf/share-batch-processor-executor
Draft

perf: Share one executor between log and metrics batch processors (JAVA-653)#5818
runningcode wants to merge 2 commits into
mainfrom
no/perf/share-batch-processor-executor

Conversation

@runningcode

@runningcoderunningcode commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

📜 Description

LoggerBatchProcessor and MetricsBatchProcessor each constructed their own SentryExecutorService, so an app with both logs and metrics enabled ran two dedicated threads for structurally identical work (a 5-second flush loop that batches events and hands them to the transport).

SentryClient now owns a single SentryExecutorService, created only when logs or metrics are enabled, and exposes it via getBatchProcessorExecutorService(). The default factories inject it into both processors (through the existing 3-arg LoggerBatchProcessor constructor and a new matching one on MetricsBatchProcessor). The pluggable factory interfaces are unchanged.

The shutdown paths already close the executor from each processor's close(); since the executor is now shared, the second close is a safe no-op, and the restart branch's submit(...) is guarded with the same RejectedExecutionException fallback already used in Scopes.close() for the main executor.

💡 Motivation and Context

Part of reducing the number of threads created by the SDK: JAVA-653.

Saves one thread for every app that has both logs and metrics enabled. The executor is created only when at least one of logs or metrics is enabled, and its worker thread is spawned only when the first flush is scheduled.

Note for reviewers

Custom ILoggerBatchProcessorFactory / IMetricsBatchProcessorFactory implementations that call the public 2-arg processor constructors still get an independent executor (unchanged behavior). Only the default factories opt into the shared one.

💚 How did you test it?

New SentryClientTest case asserting both processors receive the same executor instance (and that it is the client's shared one), plus the existing LoggerBatchProcessorTest, MetricsBatchProcessorTest, SentryClientTest, LoggerApiTest, and MetricsApiTest suites.

📝 Checklist

  • I added GH Issue ID & Linear ID
  • I added tests to verify the changes.
  • No new PII added or SDK only sends newly added PII if sendDefaultPII is enabled.
  • I updated the docs if needed.
  • I updated the wizard if needed.
  • Review from the native team if needed.
  • No breaking change or entry added to the changelog.
  • No breaking change for hybrid SDKs or communicated to hybrid SDKs.

🔮 Next steps

Related PRs in this effort: RateLimiter (#5814), LifecycleWatcher (#5819), performance collector (#5816), HostnameCache (#5817).

🤖 Generated with Claude Code

@linear-code

Copy link
Copy Markdown

JAVA-653

@sentry

sentryBot commented Jul 22, 2026

Copy link
Copy Markdown

📲 Install Builds

Android

🔗 App NameApp IDVersionConfiguration
SDK Sizeio.sentry.tests.size8.50.0 (1)release

⚙️ sentry-android Build Distribution Settings

@github-actions

github-actionsBot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Performance metrics 🚀

PlainWith SentryDiff
Startup time427.22 ms526.69 ms99.48 ms
Size0 B0 B0 B

Baseline results on branch: main

Startup times

RevisionPlainWith SentryDiff
eb95ded317.51 ms369.08 ms51.57 ms
2124a46319.19 ms415.04 ms95.85 ms
c3ee041310.64 ms361.90 ms51.26 ms
dcc6bbf382.58 ms462.13 ms79.54 ms
7a19fee315.46 ms368.62 ms53.16 ms
9054d65330.94 ms403.24 ms72.30 ms
d500866326.13 ms378.70 ms52.58 ms
ad8da22365.86 ms427.00 ms61.14 ms
ed33deb337.52 ms484.06 ms146.54 ms
d15471f310.26 ms377.04 ms66.78 ms

App size

RevisionPlainWith SentryDiff
eb95ded0 B0 B0 B
2124a461.58 MiB2.12 MiB551.51 KiB
c3ee0410 B0 B0 B
dcc6bbf1.58 MiB2.12 MiB553.10 KiB
7a19fee0 B0 B0 B
9054d651.58 MiB2.29 MiB723.38 KiB
d5008660 B0 B0 B
ad8da221.58 MiB2.29 MiB719.83 KiB
ed33deb1.58 MiB2.13 MiB559.52 KiB
d15471f1.58 MiB2.13 MiB559.54 KiB

runningcodeand others added 2 commits July 22, 2026 17:54
…VA-653)
The log and metrics batch processors each created their own
SentryExecutorService, so an app using both spawned two threads for
work that is identical in shape (a 5s flush loop that hands envelopes
to the transport). SentryClient now owns a single executor, created
only when logs or metrics are enabled, and injects it into both
processors via the default factories. The restart shutdown path
tolerates the shared executor already being closed by the sibling
processor.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@runningcode
runningcodeforce-pushed the no/perf/share-batch-processor-executor branch from bb143cc to 875b0eaCompareJuly 22, 2026 15:55
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@runningcode