chore: (For Discussion): Dynamic runtime detection & Joinable handle abstraction#3413
Conversation
Codecov Report❌ Patch coverage is 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. 🚀 New features to boost your workflow:
|
| Thread(std::thread::JoinHandle<T>), | ||
| #[cfg(feature = "rt-tokio")] | ||
| TokioTask(tokio::task::JoinHandle<T>), | ||
| } |
There was a problem hiding this comment.
Wondering if this should be associated type instead of enum, for extensibility - to allow users to bring their own Runtime implementation.
There was a problem hiding this comment.
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.
| 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> |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Good catch - I think we should decide if we want public runtime extensibility or not - probably actually yes?
There was a problem hiding this comment.
See comment above - i've added this to the change to maintain extensibility.
133ae03 to
705102d
Compare
705102d to
8665f40
Compare
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 astd::thread::JoinHandleor atokio::task::JoinHandle.Key changes:
Runtime::spawnnow returnsJoinable<T>instead of(), capturing the handle to the spawned workJoinable::join()blocks until the task completes — usingthread::join()for OS threads orfutures_executor::block_on(handle)for Tokio tasksblock_onfrom theRuntimetrait (no longer needed since shutdown can justjoin()the spawned task)Joinableto directly join on their background task at shutdown, replacing the currentoneshotchannel patternThis 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 theNoAsyncruntime and the 'regular' processors, but I think this is something that would happen downstream to this approach shaking out well .