Skip to content

fix(spring-jakarta): [Queue Instrumentation 9] Clean up stale ThreadLocal context in Kafka consumer interceptor#5279

Draft
adinauer wants to merge 1 commit intofix/queue-instrumentation-otel-dedupfrom
fix/queue-instrumentation-threadlocal-cleanup
Draft

fix(spring-jakarta): [Queue Instrumentation 9] Clean up stale ThreadLocal context in Kafka consumer interceptor#5279
adinauer wants to merge 1 commit intofix/queue-instrumentation-otel-dedupfrom
fix/queue-instrumentation-threadlocal-cleanup

Conversation

@adinauer
Copy link
Copy Markdown
Member

@adinauer adinauer commented Apr 10, 2026

PR Stack (Queue Instrumentation)


📜 Description

Implement clearThreadState() and defensive cleanup in intercept() on SentryKafkaRecordInterceptor to prevent ThreadLocal leaks of SentryRecordContext (lifecycle token + transaction).

Spring Kafka's RecordInterceptor extends ThreadStateProcessor, which provides clearThreadState() — called in the poll loop's finally block, making it the most reliable cleanup hook. This catches edge cases where success()/failure() callbacks are skipped (e.g. Error thrown by listener).

Also adds defensive cleanup at the start of intercept() to handle any stale context from a previous record that was not properly cleaned up.

💡 Motivation and Context

Review finding F-001 identified that SentryRecordContext stored in ThreadLocal is only cleaned in success()/failure(). While the realistic leak surface is narrow for synchronous listeners (Spring Kafka reliably calls these callbacks in most scenarios), implementing clearThreadState() is a trivially cheap safety net that Spring already calls on our instance.

💚 How did you test it?

  • Added unit test: clearThreadState cleans up stale context
  • Added unit test: clearThreadState is no-op when no context exists
  • Added unit test: intercept cleans up stale context from previous record
  • All existing tests continue to pass

📝 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

Nothing — this is a standalone defensive fix.

⚠️ Merge this PR using a merge commit (not squash). Only the collection branch is squash-merged into main.

#skip-changelog

…umer interceptor

Implement clearThreadState() and defensive cleanup in intercept() to
prevent ThreadLocal leaks of SentryRecordContext. Spring Kafka calls
clearThreadState() in the poll loop's finally block, making it the
most reliable cleanup hook for edge cases where success()/failure()
callbacks are skipped (e.g. Error thrown by listener).

Also add defensive cleanup at the start of intercept() to handle any
stale context from a previous record that was not properly cleaned up.

Co-Authored-By: Claude <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 10, 2026

Semver Impact of This PR

🟢 Patch (bug fixes)

📋 Changelog Preview

This is how your changes will appear in the changelog.
Entries from this PR are highlighted with a left border (blockquote style).


This PR will not appear in the changelog.


🤖 This preview updates automatically when you update the PR.

@sentry
Copy link
Copy Markdown

sentry bot commented Apr 10, 2026

Sentry Build Distribution

App Name App ID Version Configuration Install Page
SDK Size io.sentry.tests.size 8.37.1 (1) release Install Build

Configure sentry-android build distribution settings

@github-actions
Copy link
Copy Markdown
Contributor

Performance metrics 🚀

  Plain With Sentry Diff
Startup time 324.73 ms 382.26 ms 57.53 ms
Size 0 B 0 B 0 B

Baseline results on branch: fix/queue-instrumentation-otel-dedup

Startup times

Revision Plain With Sentry Diff
482e951 317.11 ms 375.46 ms 58.35 ms
d5c7c78 367.02 ms 442.91 ms 75.89 ms
a0ce355 308.90 ms 355.65 ms 46.75 ms

App size

Revision Plain With Sentry Diff
482e951 0 B 0 B 0 B
d5c7c78 0 B 0 B 0 B
a0ce355 0 B 0 B 0 B

Sign up for free to 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