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