Skip to content

chore: (For Discussion): Dynamic runtime detection & Joinable handle abstraction#3413

Open
scottgerring wants to merge 6 commits intoopen-telemetry:mainfrom
scottgerring:scottgerring/runtime-v3-add-join-abstraction
Open

chore: (For Discussion): Dynamic runtime detection & Joinable handle abstraction#3413
scottgerring wants to merge 6 commits intoopen-telemetry:mainfrom
scottgerring:scottgerring/runtime-v3-add-join-abstraction

Conversation

@scottgerring
Copy link
Copy Markdown
Member

@scottgerring scottgerring commented Mar 11, 2026

Fixes #2643, stabilising Runtime trait.

Builds on all of the dynamic runtime detection changes from #3412 and goes further by introducing a Joinable<T> type - a unified join handle that wraps either a std::thread::JoinHandle or a tokio::task::JoinHandle.

Key changes:

  • Runtime::spawn now returns Joinable<T> instead of (), capturing the handle to the spawned work
  • Joinable::join() blocks until the task completes — using thread::join() for OS threads or futures_executor::block_on(handle) for Tokio tasks
  • Removes block_on from the Runtime trait (no longer needed since shutdown can just join() the spawned task)
  • Processors use the returned Joinable to directly join on their background task at shutdown, replacing the current oneshot channel pattern

This is a deeper refactor that simplifies shutdown logic across all three signal processors (traces, metrics, logs) by making the spawn-and-join lifecycle explicit rather than relying on side-channel signalling.

Other alternatives?
We could look at removing the processors that are explicitly threaded (e.g. BatchLogProcessor, BatchSpanProcessor) in favour of the NoAsync runtime and the 'regular' processors, but I think this is something that would happen downstream to this approach shaking out well .

@codecov
Copy link
Copy Markdown

codecov Bot commented Mar 11, 2026

Codecov Report

❌ Patch coverage is 80.25478% with 31 lines in your changes missing coverage. Please review.
✅ Project coverage is 83.7%. Comparing base (d91b847) to head (8665f40).
⚠️ Report is 40 commits behind head on main.

Files with missing lines Patch % Lines
opentelemetry-sdk/src/runtime.rs 67.3% 15 Missing ⚠️
.../src/metrics/periodic_reader_with_async_runtime.rs 86.9% 6 Missing ⚠️
...y-sdk/src/logs/log_processor_with_async_runtime.rs 78.2% 5 Missing ⚠️
...sdk/src/trace/span_processor_with_async_runtime.rs 88.0% 5 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff           @@
##            main   #3413     +/-   ##
=======================================
+ Coverage   83.1%   83.7%   +0.5%     
=======================================
  Files        128     126      -2     
  Lines      24899   25418    +519     
=======================================
+ Hits       20715   21280    +565     
+ Misses      4184    4138     -46     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Thread(std::thread::JoinHandle<T>),
#[cfg(feature = "rt-tokio")]
TokioTask(tokio::task::JoinHandle<T>),
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wondering if this should be associated type instead of enum, for extensibility - to allow users to bring their own Runtime implementation.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've set this up in this commit --> 133ae03

I've added a public JoinHandle<T> trait. Runtime::spawn now returns an associated type SpawnHandle<T> bounded on JoinHandle<T>, so external runtime implementors can bring their own handle type rather than being coupled to the built-in Joinable enum.

Joinable itself is still there as the concrete impl used by Tokio and NoAsync, but it's #[doc(hidden)] (can't actually make it pub(crate) it turns out).

I've also kept spawn generic over T rather than fixing Output = (), since the flexibility is easy enough now and avoids a future breaking change if callers ever want to retrieve a result from a spawned task.

Comment thread opentelemetry-sdk/src/runtime.rs Outdated
fn spawn<F>(&self, future: F)
/// This is mainly used to run batch span processing in the background. The mechanism used
/// to provide the spawn may be relatively heavyweight.
fn spawn<F, T>(&self, future: F) -> Joinable<T>
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should spawn return an associated handle type instead of Joinable<T>? As written, the concrete enum makes the public Runtime trait effectively non-extensible for external runtimes.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch - I think we should decide if we want public runtime extensibility or not - probably actually yes?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See comment above - i've added this to the change to maintain extensibility.

@scottgerring scottgerring marked this pull request as ready for review May 5, 2026 05:19
@scottgerring scottgerring requested a review from a team as a code owner May 5, 2026 05:19
@scottgerring scottgerring force-pushed the scottgerring/runtime-v3-add-join-abstraction branch from 133ae03 to 705102d Compare May 5, 2026 05:19
@scottgerring scottgerring force-pushed the scottgerring/runtime-v3-add-join-abstraction branch from 705102d to 8665f40 Compare May 5, 2026 05:23
@scottgerring scottgerring requested a review from cijothomas May 5, 2026 05:23
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.

Stabilize support for async runtimes

2 participants