sync_run_async/
sync_run_async.rs1crate::ix!();
2
3pub fn sync_run_async<F, T>(fut: F) -> T
12where
13 F: std::future::Future<Output = T> + Send + 'static,
14 T: Send + 'static,
15{
16 use tokio::runtime::{Handle, Runtime};
17 use tracing::{debug, error, info, warn};
18
19 info!("Attempting to run async code from a sync context without nesting a runtime");
20
21 match Handle::try_current() {
22 Ok(handle) => {
23 debug!("Found an existing Tokio runtime handle; using it to block on the future");
24 std::thread::scope(|s| {
25 let join_handle = s.spawn(|| handle.block_on(fut));
29 join_handle.join().unwrap_or_else(|panic_err| {
30 error!("Thread panicked while running async code: {:?}", panic_err);
31 panic!("Nested runtime usage or thread panic in sync_run_async")
32 })
33 })
34 }
35 Err(_) => {
36 warn!("No existing runtime found; creating a temporary one just for this block");
37 let rt = Runtime::new().expect("Failed to create temporary Tokio runtime");
38 rt.block_on(fut)
39 }
40 }
41}
42
43#[cfg(test)]
44mod run_async_without_nested_runtime_tests {
45 use super::*;
46
47 #[traced_test]
50 fn test_run_async_without_nested_runtime_fresh() {
51 let result = sync_run_async(async {
52 40 + 2
53 });
54 assert_eq!(result, 42, "Should have successfully computed 42 asynchronously");
55 }
56
57 #[traced_test]
59 fn test_run_async_without_nested_runtime_in_existing_runtime() {
60 let rt = tokio::runtime::Runtime::new().expect("Failed to create runtime");
61 rt.block_on(async {
62 let result = sync_run_async(async {
63 50 + 8
64 });
65 assert_eq!(result, 58, "Should have successfully computed 58 asynchronously");
66 });
67 }
68}