@@ -367,6 +367,8 @@ impl NodeBuilder {
367367 ///
368368 /// If not provided, the node will spawn its own runtime or reuse any outer runtime context it
369369 /// can detect.
370+ ///
371+ /// Note we require the given runtime to be of the `multithreaded` flavor.
370372 #[ cfg_attr( feature = "uniffi" , allow( dead_code) ) ]
371373 pub fn set_runtime ( & mut self , runtime_handle : tokio:: runtime:: Handle ) -> & mut Self {
372374 self . runtime_handle = Some ( runtime_handle) ;
@@ -910,14 +912,24 @@ impl NodeBuilder {
910912 }
911913
912914 fn setup_runtime ( & self , logger : & Arc < Logger > ) -> Result < Arc < Runtime > , BuildError > {
913- if let Some ( handle) = self . runtime_handle . as_ref ( ) {
914- Ok ( Arc :: new ( Runtime :: with_handle ( handle. clone ( ) , Arc :: clone ( logger) ) ) )
915+ let runtime = if let Some ( handle) = self . runtime_handle . as_ref ( ) {
916+ Arc :: new ( Runtime :: with_handle ( handle. clone ( ) , Arc :: clone ( logger) ) )
915917 } else {
916- Ok ( Arc :: new ( Runtime :: new ( Arc :: clone ( logger) ) . map_err ( |e| {
918+ Arc :: new ( Runtime :: new ( Arc :: clone ( logger) ) . map_err ( |e| {
917919 log_error ! ( logger, "Failed to setup tokio runtime: {}" , e) ;
918920 BuildError :: RuntimeSetupFailed
919- } ) ?) )
921+ } ) ?)
922+ } ;
923+
924+ if runtime. handle ( ) . runtime_flavor ( ) != tokio:: runtime:: RuntimeFlavor :: MultiThread {
925+ log_error ! (
926+ logger,
927+ "Failed to setup tokio runtime: we require a multithreaded runtime."
928+ ) ;
929+ return Err ( BuildError :: RuntimeSetupFailed ) ;
920930 }
931+
932+ Ok ( runtime)
921933 }
922934
923935 fn build_with_store_and_logger < S : PaginatedKVStore + Send + Sync + ' static > (
@@ -2698,4 +2710,33 @@ mod tests {
26982710 let node = sanitize_alias ( alias) ;
26992711 assert_eq ! ( node. err( ) . unwrap( ) , BuildError :: InvalidNodeAlias ) ;
27002712 }
2713+
2714+ #[ test]
2715+ fn rejects_non_multithreaded_runtimes ( ) {
2716+ let logger = Arc :: new ( Logger :: new_log_facade ( ) ) ;
2717+ let current_thread_runtime =
2718+ tokio:: runtime:: Builder :: new_current_thread ( ) . enable_all ( ) . build ( ) . unwrap ( ) ;
2719+
2720+ let mut builder = NodeBuilder :: new ( ) ;
2721+ builder. set_runtime ( current_thread_runtime. handle ( ) . clone ( ) ) ;
2722+ assert_eq ! (
2723+ builder. setup_runtime( & logger) . err( ) ,
2724+ Some ( BuildError :: RuntimeSetupFailed ) ,
2725+ "a current-thread runtime given via `set_runtime` should be rejected"
2726+ ) ;
2727+
2728+ current_thread_runtime. block_on ( async {
2729+ assert_eq ! (
2730+ NodeBuilder :: new( ) . setup_runtime( & logger) . err( ) ,
2731+ Some ( BuildError :: RuntimeSetupFailed ) ,
2732+ "a detected outer current-thread runtime context should be rejected"
2733+ ) ;
2734+ } ) ;
2735+
2736+ let multi_thread_runtime =
2737+ tokio:: runtime:: Builder :: new_multi_thread ( ) . enable_all ( ) . build ( ) . unwrap ( ) ;
2738+ let mut builder = NodeBuilder :: new ( ) ;
2739+ builder. set_runtime ( multi_thread_runtime. handle ( ) . clone ( ) ) ;
2740+ assert ! ( builder. setup_runtime( & logger) . is_ok( ) , "a multi-threaded runtime should be used" ) ;
2741+ }
27012742}
0 commit comments