@@ -128,8 +128,8 @@ pub use builder::NodeBuilder as Builder;
128
128
use chain:: ChainSource ;
129
129
use config:: {
130
130
default_user_config, may_announce_channel, ChannelConfig , Config ,
131
- LDK_EVENT_HANDLER_SHUTDOWN_TIMEOUT_SECS , NODE_ANN_BCAST_INTERVAL , PEER_RECONNECTION_INTERVAL ,
132
- RGS_SYNC_INTERVAL ,
131
+ BACKGROUND_TASK_SHUTDOWN_TIMEOUT_SECS , LDK_EVENT_HANDLER_SHUTDOWN_TIMEOUT_SECS ,
132
+ NODE_ANN_BCAST_INTERVAL , PEER_RECONNECTION_INTERVAL , RGS_SYNC_INTERVAL ,
133
133
} ;
134
134
use connection:: ConnectionManager ;
135
135
use event:: { EventHandler , EventQueue } ;
@@ -180,6 +180,8 @@ pub struct Node {
180
180
runtime : Arc < RwLock < Option < Arc < tokio:: runtime:: Runtime > > > > ,
181
181
stop_sender : tokio:: sync:: watch:: Sender < ( ) > ,
182
182
background_processor_task : Mutex < Option < tokio:: task:: JoinHandle < ( ) > > > ,
183
+ background_tasks : Mutex < Option < tokio:: task:: JoinSet < ( ) > > > ,
184
+ cancellable_background_tasks : Mutex < Option < tokio:: task:: JoinSet < ( ) > > > ,
183
185
config : Arc < Config > ,
184
186
wallet : Arc < Wallet > ,
185
187
chain_source : Arc < ChainSource > ,
@@ -233,6 +235,10 @@ impl Node {
233
235
return Err ( Error :: AlreadyRunning ) ;
234
236
}
235
237
238
+ let mut background_tasks = tokio:: task:: JoinSet :: new ( ) ;
239
+ let mut cancellable_background_tasks = tokio:: task:: JoinSet :: new ( ) ;
240
+ let runtime_handle = runtime. handle ( ) ;
241
+
236
242
log_info ! (
237
243
self . logger,
238
244
"Starting up LDK Node with node ID {} on network: {}" ,
@@ -259,19 +265,27 @@ impl Node {
259
265
let sync_cman = Arc :: clone ( & self . channel_manager ) ;
260
266
let sync_cmon = Arc :: clone ( & self . chain_monitor ) ;
261
267
let sync_sweeper = Arc :: clone ( & self . output_sweeper ) ;
262
- runtime. spawn ( async move {
263
- chain_source
264
- . continuously_sync_wallets ( stop_sync_receiver, sync_cman, sync_cmon, sync_sweeper)
265
- . await ;
266
- } ) ;
268
+ background_tasks. spawn_on (
269
+ async move {
270
+ chain_source
271
+ . continuously_sync_wallets (
272
+ stop_sync_receiver,
273
+ sync_cman,
274
+ sync_cmon,
275
+ sync_sweeper,
276
+ )
277
+ . await ;
278
+ } ,
279
+ runtime_handle,
280
+ ) ;
267
281
268
282
if self . gossip_source . is_rgs ( ) {
269
283
let gossip_source = Arc :: clone ( & self . gossip_source ) ;
270
284
let gossip_sync_store = Arc :: clone ( & self . kv_store ) ;
271
285
let gossip_sync_logger = Arc :: clone ( & self . logger ) ;
272
286
let gossip_node_metrics = Arc :: clone ( & self . node_metrics ) ;
273
287
let mut stop_gossip_sync = self . stop_sender . subscribe ( ) ;
274
- runtime . spawn ( async move {
288
+ cancellable_background_tasks . spawn_on ( async move {
275
289
let mut interval = tokio:: time:: interval ( RGS_SYNC_INTERVAL ) ;
276
290
loop {
277
291
tokio:: select! {
@@ -312,7 +326,7 @@ impl Node {
312
326
}
313
327
}
314
328
}
315
- } ) ;
329
+ } , runtime_handle ) ;
316
330
}
317
331
318
332
if let Some ( listening_addresses) = & self . config . listening_addresses {
@@ -338,7 +352,7 @@ impl Node {
338
352
bind_addrs. extend ( resolved_address) ;
339
353
}
340
354
341
- runtime . spawn ( async move {
355
+ cancellable_background_tasks . spawn_on ( async move {
342
356
{
343
357
let listener =
344
358
tokio:: net:: TcpListener :: bind ( & * bind_addrs) . await
@@ -357,7 +371,7 @@ impl Node {
357
371
_ = stop_listen. changed( ) => {
358
372
log_debug!(
359
373
listening_logger,
360
- "Stopping listening to inbound connections." ,
374
+ "Stopping listening to inbound connections."
361
375
) ;
362
376
break ;
363
377
}
@@ -376,7 +390,7 @@ impl Node {
376
390
}
377
391
378
392
listening_indicator. store ( false , Ordering :: Release ) ;
379
- } ) ;
393
+ } , runtime_handle ) ;
380
394
}
381
395
382
396
// Regularly reconnect to persisted peers.
@@ -385,15 +399,15 @@ impl Node {
385
399
let connect_logger = Arc :: clone ( & self . logger ) ;
386
400
let connect_peer_store = Arc :: clone ( & self . peer_store ) ;
387
401
let mut stop_connect = self . stop_sender . subscribe ( ) ;
388
- runtime . spawn ( async move {
402
+ cancellable_background_tasks . spawn_on ( async move {
389
403
let mut interval = tokio:: time:: interval ( PEER_RECONNECTION_INTERVAL ) ;
390
404
interval. set_missed_tick_behavior ( tokio:: time:: MissedTickBehavior :: Skip ) ;
391
405
loop {
392
406
tokio:: select! {
393
407
_ = stop_connect. changed( ) => {
394
408
log_debug!(
395
409
connect_logger,
396
- "Stopping reconnecting known peers." ,
410
+ "Stopping reconnecting known peers."
397
411
) ;
398
412
return ;
399
413
}
@@ -413,7 +427,7 @@ impl Node {
413
427
}
414
428
}
415
429
}
416
- } ) ;
430
+ } , runtime_handle ) ;
417
431
418
432
// Regularly broadcast node announcements.
419
433
let bcast_cm = Arc :: clone ( & self . channel_manager ) ;
@@ -425,7 +439,7 @@ impl Node {
425
439
let mut stop_bcast = self . stop_sender . subscribe ( ) ;
426
440
let node_alias = self . config . node_alias . clone ( ) ;
427
441
if may_announce_channel ( & self . config ) . is_ok ( ) {
428
- runtime . spawn ( async move {
442
+ cancellable_background_tasks . spawn_on ( async move {
429
443
// We check every 30 secs whether our last broadcast is NODE_ANN_BCAST_INTERVAL away.
430
444
#[ cfg( not( test) ) ]
431
445
let mut interval = tokio:: time:: interval ( Duration :: from_secs ( 30 ) ) ;
@@ -496,7 +510,7 @@ impl Node {
496
510
}
497
511
}
498
512
}
499
- } ) ;
513
+ } , runtime_handle ) ;
500
514
}
501
515
502
516
let mut stop_tx_bcast = self . stop_sender . subscribe ( ) ;
@@ -605,24 +619,33 @@ impl Node {
605
619
let mut stop_liquidity_handler = self . stop_sender . subscribe ( ) ;
606
620
let liquidity_handler = Arc :: clone ( & liquidity_source) ;
607
621
let liquidity_logger = Arc :: clone ( & self . logger ) ;
608
- runtime. spawn ( async move {
609
- loop {
610
- tokio:: select! {
611
- _ = stop_liquidity_handler. changed( ) => {
612
- log_debug!(
613
- liquidity_logger,
614
- "Stopping processing liquidity events." ,
615
- ) ;
616
- return ;
622
+ background_tasks. spawn_on (
623
+ async move {
624
+ loop {
625
+ tokio:: select! {
626
+ _ = stop_liquidity_handler. changed( ) => {
627
+ log_debug!(
628
+ liquidity_logger,
629
+ "Stopping processing liquidity events." ,
630
+ ) ;
631
+ return ;
632
+ }
633
+ _ = liquidity_handler. handle_next_event( ) => { }
617
634
}
618
- _ = liquidity_handler. handle_next_event( ) => { }
619
635
}
620
- }
621
- } ) ;
636
+ } ,
637
+ runtime_handle,
638
+ ) ;
622
639
}
623
640
624
641
* runtime_lock = Some ( runtime) ;
625
642
643
+ debug_assert ! ( self . background_tasks. lock( ) . unwrap( ) . is_none( ) ) ;
644
+ * self . background_tasks . lock ( ) . unwrap ( ) = Some ( background_tasks) ;
645
+
646
+ debug_assert ! ( self . cancellable_background_tasks. lock( ) . unwrap( ) . is_none( ) ) ;
647
+ * self . cancellable_background_tasks . lock ( ) . unwrap ( ) = Some ( cancellable_background_tasks) ;
648
+
626
649
log_info ! ( self . logger, "Startup complete." ) ;
627
650
Ok ( ( ) )
628
651
}
@@ -653,6 +676,17 @@ impl Node {
653
676
} ,
654
677
}
655
678
679
+ // Cancel cancellable background tasks
680
+ if let Some ( mut tasks) = self . cancellable_background_tasks . lock ( ) . unwrap ( ) . take ( ) {
681
+ let runtime_2 = Arc :: clone ( & runtime) ;
682
+ tasks. abort_all ( ) ;
683
+ tokio:: task:: block_in_place ( move || {
684
+ runtime_2. block_on ( async { while let Some ( _) = tasks. join_next ( ) . await { } } )
685
+ } ) ;
686
+ } else {
687
+ debug_assert ! ( false , "Expected some cancellable background tasks" ) ;
688
+ } ;
689
+
656
690
// Disconnect all peers.
657
691
self . peer_manager . disconnect_all_peers ( ) ;
658
692
log_debug ! ( self . logger, "Disconnected all network peers." ) ;
@@ -661,6 +695,46 @@ impl Node {
661
695
self . chain_source . stop ( ) ;
662
696
log_debug ! ( self . logger, "Stopped chain sources." ) ;
663
697
698
+ // Wait until non-cancellable background tasks (mod LDK's background processor) are done.
699
+ let runtime_3 = Arc :: clone ( & runtime) ;
700
+ if let Some ( mut tasks) = self . background_tasks . lock ( ) . unwrap ( ) . take ( ) {
701
+ tokio:: task:: block_in_place ( move || {
702
+ runtime_3. block_on ( async {
703
+ loop {
704
+ let timeout_fut = tokio:: time:: timeout (
705
+ Duration :: from_secs ( BACKGROUND_TASK_SHUTDOWN_TIMEOUT_SECS ) ,
706
+ tasks. join_next_with_id ( ) ,
707
+ ) ;
708
+ match timeout_fut. await {
709
+ Ok ( Some ( Ok ( ( id, _) ) ) ) => {
710
+ log_trace ! ( self . logger, "Stopped background task with id {}" , id) ;
711
+ } ,
712
+ Ok ( Some ( Err ( e) ) ) => {
713
+ tasks. abort_all ( ) ;
714
+ log_trace ! ( self . logger, "Stopping background task failed: {}" , e) ;
715
+ break ;
716
+ } ,
717
+ Ok ( None ) => {
718
+ log_debug ! ( self . logger, "Stopped all background tasks" ) ;
719
+ break ;
720
+ } ,
721
+ Err ( e) => {
722
+ tasks. abort_all ( ) ;
723
+ log_error ! (
724
+ self . logger,
725
+ "Stopping background task timed out: {}" ,
726
+ e
727
+ ) ;
728
+ break ;
729
+ } ,
730
+ }
731
+ }
732
+ } )
733
+ } ) ;
734
+ } else {
735
+ debug_assert ! ( false , "Expected some background tasks" ) ;
736
+ } ;
737
+
664
738
// Wait until background processing stopped, at least until a timeout is reached.
665
739
if let Some ( background_processor_task) =
666
740
self . background_processor_task . lock ( ) . unwrap ( ) . take ( )
@@ -694,7 +768,9 @@ impl Node {
694
768
log_error ! ( self . logger, "Stopping event handling timed out: {}" , e) ;
695
769
} ,
696
770
}
697
- }
771
+ } else {
772
+ debug_assert ! ( false , "Expected a background processing task" ) ;
773
+ } ;
698
774
699
775
#[ cfg( tokio_unstable) ]
700
776
{
0 commit comments