Repository navigation
Add sampler shutdown lifecycle - #5747
Mayukhga83 wants to merge 4 commits into
Conversation
Forward shutdown through wrapper samplers and invoke it from TracerProvider with idempotent cleanup semantics. Assisted-by: ChatGPT
|
|
Pull request dashboard statusWaiting on the author · refreshed 2026-11-04 04:09 UTC Respond to 4 review items (e.g. link a commit, explain why not, ask a follow-up): Status above doesn't look right?
|
| def get_description(self) -> str: | ||
| pass | ||
|
|
||
| def shutdown(self) -> None: |
There was a problem hiding this comment.
This needs to be private since it's developmental
There was a problem hiding this comment.
Changed the developmental lifecycle hook to private _shutdown() and updated wrappers/tests
| if self._shutdown: | ||
| return | ||
| self._shutdown = True | ||
| try: |
There was a problem hiding this comment.
nit: extract these into helpers to avoid nested try-finally
There was a problem hiding this comment.
Extracted sampler shutdown and atexit cleanup into helpers, removing the nested try/finally while preserving cleanup behavior
| @@ -1279,6 +1279,8 @@ def __init__( | |||
| self._disabled = disabled.lower().strip() == "true" | |||
There was a problem hiding this comment.
Please add a changelog entry.
There was a problem hiding this comment.
Added .changelog/5747.added for the SDK sampler shutdown lifecycle
This comment has been minimized.
This comment has been minimized.
Assisted-by: ChatGPT 5
|
Addressed the three review items in 17d8851. The focused tests pass: 137 passed, 1 platform-specific skip |
tammy-baylis-swi
left a comment
There was a problem hiding this comment.
Thank you, this lgtm. Not sure why the changelog ci/cd is failing. Please could you Update Branch which might stop the symbol failure.
|
Update from main has fixed the ci/cd. 🙂 Maintainers ptal at the revisions made |
This comment has been minimized.
This comment has been minimized.
|
/dashboard route:reviewers |
|
@tammy-baylis-swi, your reviewer-routing request was recorded; this pull request has the approvals it needs and is now waiting on maintainers. The handoff remains active across pushes until newer actionable human feedback arrives. Top-level feedback through this request will not return; unresolved review threads remain open. |
pmcollins
left a comment
There was a problem hiding this comment.
Thanks, LGTM overall. Added one comment.
| for delegate in delegates: | ||
| if id(delegate) not in seen: | ||
| seen.add(id(delegate)) | ||
| delegate._shutdown() # pylint: disable=protected-access |
There was a problem hiding this comment.
Looks like this can raise an exception, in which case the remaining delegates won't be shut down. Can we catch any exceptions and continue shutting down remaining delegates, then handle the error?
There was a problem hiding this comment.
🟡 Changes recommended
Shutdown bypasses the advertised public sampler hook, while delegate or processor failures can permanently prevent remaining resources from being cleaned up.
3 open issues
What changed in this PR
Adds a sampler shutdown lifecycle to the tracing SDK, supporting resource cleanup for samplers as requested in #5713.
Changes:
- Adds a default no-op sampler cleanup hook and forwarding through wrapper samplers.
- Makes provider shutdown idempotent and attempts sampler cleanup after span processors, including when processor shutdown raises.
- Adds lifecycle tests and a changelog entry.
| File | Description |
|---|---|
opentelemetry-sdk/tests/trace/test_trace.py |
Tests shutdown ordering, repeated calls, exit cleanup, and failures. |
opentelemetry-sdk/tests/trace/test_sampling.py |
Tests default cleanup, wrapper forwarding, and delegate deduplication. |
opentelemetry-sdk/src/opentelemetry/sdk/trace/sampling.py |
Adds sampler cleanup hooks and wrapper propagation. |
opentelemetry-sdk/src/opentelemetry/sdk/trace/__init__.py |
Integrates sampler cleanup into guarded, once-only provider shutdown. |
.changelog/5747.added |
Announces the sampler shutdown lifecycle. |
Review effort: Balanced
| self._shutdown = True | ||
| try: | ||
| self._active_span_processor.shutdown() |
| def get_description(self) -> str: | ||
| pass | ||
|
|
||
| def _shutdown(self) -> None: |
| for delegate in delegates: | ||
| if id(delegate) not in seen: | ||
| seen.add(id(delegate)) | ||
| delegate._shutdown() # pylint: disable=protected-access |

Description
This PR adds a shutdown lifecycle to SDK samplers.
Sampler.shutdown()has a default no-op implementation so existing custom samplers remain compatible.TracerProvider.shutdown()now shuts down span processors first and then the configured sampler.Wrapper samplers also forward shutdown to their delegates:
ParentBasedshuts down each distinct directly wrapped sampler once.AlwaysRecordSamplershuts down its root sampler.Provider shutdown is idempotent, including when explicit shutdown and process-exit cleanup both occur. Cleanup is still attempted when another shutdown component raises an exception.
Part of #5713.
Assisted-by: ChatGPT
Type of change
How Has This Been Tested?
I added unit tests covering:
shutdown()ParentBasedParentBaseddelegate positionsAlwaysRecordSamplerValidation performed:
lint-opentelemetry-sdkpassedDoes This PR Require a Contrib Repo Change?
Checklist