open-telemetry / open-telemetry/opentelemetry-python
ConcurrentMultiSpanProcessor: cannot schedule new futures after shutdown
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 2.6k
- Forks
- 1k
- Avg merge
- 4d 15h
- Merged PRs (30d)
- 19
Description
Describe your environment
OS: macOS 15.2
Python version: 3.13.0
Dependencies from pip install opentelemetry-sdk:
deprecated==1.2.18
importlib-metadata==8.5.0
opentelemetry-api==1.30.0
opentelemetry-sdk==1.30.0
opentelemetry-semantic-conventions==0.51b0
typing-extensions==4.12.2
wrapt==1.17.2
zipp==3.21.0
What happened?
I tried to use the opentelemetry.sdk.trace.ConcurrentMultiSpanProcessor for a library but get an error on shutdown.
Steps to Reproduce
Based on the basic_trace.py example:
from opentelemetry import trace
from opentelemetry.sdk.trace import (
ConcurrentMultiSpanProcessor,
TracerProvider,
)
from opentelemetry.sdk.trace.export import (
BatchSpanProcessor,
ConsoleSpanExporter,
)
span_proc = ConcurrentMultiSpanProcessor()
span_proc.add_span_processor(BatchSpanProcessor(ConsoleSpanExporter()))
trace.set_tracer_provider(TracerProvider())
trace.get_tracer_provider().add_span_processor(span_proc)
tracer = trace.get_tracer(__name__)
with tracer.start_as_current_span("foo"):
print("Hello world!")
Running with:
python basic_trace.py
Expected Result
Hello world!
{
"name": "foo",
"context": {
"trace_id": "0xcfd5173b1021291f64aaf996aa5a653c",
"span_id": "0x4b7f1558bcce9066",
"trace_state": "[]"
},
"kind": "SpanKind.INTERNAL",
"parent_id": null,
"start_time": "2025-03-05T13:33:42.622950Z",
"end_time": "2025-03-05T13:33:42.623034Z",
"status": {
"status_code": "UNSET"
},
"attributes": {},
"events": [],
"links": [],
"resource": {
"attributes": {
"telemetry.sdk.language": "python",
"telemetry.sdk.name": "opentelemetry",
"telemetry.sdk.version": "1.30.0",
"service.name": "unknown_service"
},
"schema_url": ""
}
}
Actual Result
Hello world!
Exception ignored in atexit callback <bound method TracerProvider.shutdown of <opentelemetry.sdk.trace.TracerProvider object at 0x100ae74d0>>:
Traceback (most recent call last):
File "/Users/helder/Projects/opentelemetry-python/docs/examples/basic_tracer/.venv/lib/python3.13/site-packages/opentelemetry/sdk/trace/__init__.py", line 1282, in shutdown
self._active_span_processor.shutdown()
File "/Users/helder/Projects/opentelemetry-python/docs/examples/basic_tracer/.venv/lib/python3.13/site-packages/opentelemetry/sdk/trace/__init__.py", line 180, in shutdown
sp.shutdown()
File "/Users/helder/Projects/opentelemetry-python/docs/examples/basic_tracer/.venv/lib/python3.13/site-packages/opentelemetry/sdk/trace/__init__.py", line 262, in shutdown
self._submit_and_await(lambda sp: sp.shutdown)
File "/Users/helder/Projects/opentelemetry-python/docs/examples/basic_tracer/.venv/lib/python3.13/site-packages/opentelemetry/sdk/trace/__init__.py", line 243, in _submit_and_await
future = self._executor.submit(func(sp), *args, **kwargs)
File "/Users/helder/Library/Application Support/uv/python/cpython-3.13.0-macos-aarch64-none/lib/python3.13/concurrent/futures/thread.py", line 170, in submit
raise RuntimeError('cannot schedule new futures after shutdown')
RuntimeError: cannot schedule new futures after shutdown
Additional context
I can avoid the error by manually shutting down in the end of the script:
trace.get_tracer_provider().shutdown()
But since the tracer provider already calls shutdown on exit, can't this be handled automatically without the manual shutdown?
Would you like to implement a fix?
None
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with opentelemetry/sdk/trace/init.py, especially ConcurrentMultiSpanProcessor._submit_and_await and TracerProvider.shutdown; compare them with the basic_trace.py reproduction. Verify the behavior when shutdown is invoked by the atexit callback, and consider the issue resolved when that example exits without the RuntimeError while still shutting down processors.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- observability-sre
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100