@@ -127,8 +127,8 @@ pub use builder::NodeBuilder as Builder;
127
127
use chain:: ChainSource ;
128
128
use config:: {
129
129
default_user_config, may_announce_channel, ChannelConfig , Config ,
130
- LDK_EVENT_HANDLER_SHUTDOWN_TIMEOUT_SECS , NODE_ANN_BCAST_INTERVAL , PEER_RECONNECTION_INTERVAL ,
131
- RGS_SYNC_INTERVAL ,
130
+ BACKGROUND_TASK_SHUTDOWN_TIMEOUT_SECS , LDK_EVENT_HANDLER_SHUTDOWN_TIMEOUT_SECS ,
131
+ NODE_ANN_BCAST_INTERVAL , PEER_RECONNECTION_INTERVAL , RGS_SYNC_INTERVAL ,
132
132
} ;
133
133
use connection:: ConnectionManager ;
134
134
use event:: { EventHandler , EventQueue } ;
@@ -179,6 +179,7 @@ pub struct Node {
179
179
runtime : Arc < RwLock < Option < Arc < tokio:: runtime:: Runtime > > > > ,
180
180
stop_sender : tokio:: sync:: watch:: Sender < ( ) > ,
181
181
background_processor_task : Mutex < Option < tokio:: task:: JoinHandle < ( ) > > > ,
182
+ background_tasks : Mutex < Option < tokio:: task:: JoinSet < ( ) > > > ,
182
183
config : Arc < Config > ,
183
184
wallet : Arc < Wallet > ,
184
185
chain_source : Arc < ChainSource > ,
@@ -232,6 +233,9 @@ impl Node {
232
233
return Err ( Error :: AlreadyRunning ) ;
233
234
}
234
235
236
+ let mut background_tasks = tokio:: task:: JoinSet :: new ( ) ;
237
+ let runtime_handle = runtime. handle ( ) ;
238
+
235
239
log_info ! (
236
240
self . logger,
237
241
"Starting up LDK Node with node ID {} on network: {}" ,
@@ -258,19 +262,27 @@ impl Node {
258
262
let sync_cman = Arc :: clone ( & self . channel_manager ) ;
259
263
let sync_cmon = Arc :: clone ( & self . chain_monitor ) ;
260
264
let sync_sweeper = Arc :: clone ( & self . output_sweeper ) ;
261
- runtime. spawn ( async move {
262
- chain_source
263
- . continuously_sync_wallets ( stop_sync_receiver, sync_cman, sync_cmon, sync_sweeper)
264
- . await ;
265
- } ) ;
265
+ background_tasks. spawn_on (
266
+ async move {
267
+ chain_source
268
+ . continuously_sync_wallets (
269
+ stop_sync_receiver,
270
+ sync_cman,
271
+ sync_cmon,
272
+ sync_sweeper,
273
+ )
274
+ . await ;
275
+ } ,
276
+ runtime_handle,
277
+ ) ;
266
278
267
279
if self . gossip_source . is_rgs ( ) {
268
280
let gossip_source = Arc :: clone ( & self . gossip_source ) ;
269
281
let gossip_sync_store = Arc :: clone ( & self . kv_store ) ;
270
282
let gossip_sync_logger = Arc :: clone ( & self . logger ) ;
271
283
let gossip_node_metrics = Arc :: clone ( & self . node_metrics ) ;
272
284
let mut stop_gossip_sync = self . stop_sender . subscribe ( ) ;
273
- runtime . spawn ( async move {
285
+ background_tasks . spawn_on ( async move {
274
286
let mut interval = tokio:: time:: interval ( RGS_SYNC_INTERVAL ) ;
275
287
loop {
276
288
tokio:: select! {
@@ -311,7 +323,7 @@ impl Node {
311
323
}
312
324
}
313
325
}
314
- } ) ;
326
+ } , runtime_handle ) ;
315
327
}
316
328
317
329
if let Some ( listening_addresses) = & self . config . listening_addresses {
@@ -337,7 +349,7 @@ impl Node {
337
349
bind_addrs. extend ( resolved_address) ;
338
350
}
339
351
340
- runtime . spawn ( async move {
352
+ background_tasks . spawn_on ( async move {
341
353
{
342
354
let listener =
343
355
tokio:: net:: TcpListener :: bind ( & * bind_addrs) . await
@@ -356,7 +368,7 @@ impl Node {
356
368
_ = stop_listen. changed( ) => {
357
369
log_debug!(
358
370
listening_logger,
359
- "Stopping listening to inbound connections." ,
371
+ "Stopping listening to inbound connections."
360
372
) ;
361
373
break ;
362
374
}
@@ -375,7 +387,7 @@ impl Node {
375
387
}
376
388
377
389
listening_indicator. store ( false , Ordering :: Release ) ;
378
- } ) ;
390
+ } , runtime_handle ) ;
379
391
}
380
392
381
393
// Regularly reconnect to persisted peers.
@@ -384,15 +396,15 @@ impl Node {
384
396
let connect_logger = Arc :: clone ( & self . logger ) ;
385
397
let connect_peer_store = Arc :: clone ( & self . peer_store ) ;
386
398
let mut stop_connect = self . stop_sender . subscribe ( ) ;
387
- runtime . spawn ( async move {
399
+ background_tasks . spawn_on ( async move {
388
400
let mut interval = tokio:: time:: interval ( PEER_RECONNECTION_INTERVAL ) ;
389
401
interval. set_missed_tick_behavior ( tokio:: time:: MissedTickBehavior :: Skip ) ;
390
402
loop {
391
403
tokio:: select! {
392
404
_ = stop_connect. changed( ) => {
393
405
log_debug!(
394
406
connect_logger,
395
- "Stopping reconnecting known peers." ,
407
+ "Stopping reconnecting known peers."
396
408
) ;
397
409
return ;
398
410
}
@@ -412,7 +424,7 @@ impl Node {
412
424
}
413
425
}
414
426
}
415
- } ) ;
427
+ } , runtime_handle ) ;
416
428
417
429
// Regularly broadcast node announcements.
418
430
let bcast_cm = Arc :: clone ( & self . channel_manager ) ;
@@ -424,7 +436,7 @@ impl Node {
424
436
let mut stop_bcast = self . stop_sender . subscribe ( ) ;
425
437
let node_alias = self . config . node_alias . clone ( ) ;
426
438
if may_announce_channel ( & self . config ) . is_ok ( ) {
427
- runtime . spawn ( async move {
439
+ background_tasks . spawn_on ( async move {
428
440
// We check every 30 secs whether our last broadcast is NODE_ANN_BCAST_INTERVAL away.
429
441
#[ cfg( not( test) ) ]
430
442
let mut interval = tokio:: time:: interval ( Duration :: from_secs ( 30 ) ) ;
@@ -495,14 +507,15 @@ impl Node {
495
507
}
496
508
}
497
509
}
498
- } ) ;
510
+ } , runtime_handle ) ;
499
511
}
500
512
501
513
let stop_tx_bcast = self . stop_sender . subscribe ( ) ;
502
514
let chain_source = Arc :: clone ( & self . chain_source ) ;
503
- runtime. spawn ( async move {
504
- chain_source. continuously_process_broadcast_queue ( stop_tx_bcast) . await
505
- } ) ;
515
+ background_tasks. spawn_on (
516
+ async move { chain_source. continuously_process_broadcast_queue ( stop_tx_bcast) . await } ,
517
+ runtime_handle,
518
+ ) ;
506
519
507
520
let bump_tx_event_handler = Arc :: new ( BumpTransactionEventHandler :: new (
508
521
Arc :: clone ( & self . tx_broadcaster ) ,
@@ -587,24 +600,30 @@ impl Node {
587
600
let mut stop_liquidity_handler = self . stop_sender . subscribe ( ) ;
588
601
let liquidity_handler = Arc :: clone ( & liquidity_source) ;
589
602
let liquidity_logger = Arc :: clone ( & self . logger ) ;
590
- runtime. spawn ( async move {
591
- loop {
592
- tokio:: select! {
593
- _ = stop_liquidity_handler. changed( ) => {
594
- log_debug!(
595
- liquidity_logger,
596
- "Stopping processing liquidity events." ,
597
- ) ;
598
- return ;
603
+ background_tasks. spawn_on (
604
+ async move {
605
+ loop {
606
+ tokio:: select! {
607
+ _ = stop_liquidity_handler. changed( ) => {
608
+ log_debug!(
609
+ liquidity_logger,
610
+ "Stopping processing liquidity events." ,
611
+ ) ;
612
+ return ;
613
+ }
614
+ _ = liquidity_handler. handle_next_event( ) => { }
599
615
}
600
- _ = liquidity_handler. handle_next_event( ) => { }
601
616
}
602
- }
603
- } ) ;
617
+ } ,
618
+ runtime_handle,
619
+ ) ;
604
620
}
605
621
606
622
* runtime_lock = Some ( runtime) ;
607
623
624
+ debug_assert ! ( self . background_tasks. lock( ) . unwrap( ) . is_none( ) ) ;
625
+ * self . background_tasks . lock ( ) . unwrap ( ) = Some ( background_tasks) ;
626
+
608
627
log_info ! ( self . logger, "Startup complete." ) ;
609
628
Ok ( ( ) )
610
629
}
@@ -643,6 +662,44 @@ impl Node {
643
662
self . chain_source . stop ( ) ;
644
663
log_debug ! ( self . logger, "Stopped chain sources." ) ;
645
664
665
+ // Wait until all background tasks (mod LDK's background processor) are done.
666
+ let runtime_2 = Arc :: clone ( & runtime) ;
667
+ if let Some ( mut tasks) = self . background_tasks . lock ( ) . unwrap ( ) . take ( ) {
668
+ tokio:: task:: block_in_place ( move || {
669
+ runtime_2. block_on ( async {
670
+ loop {
671
+ let timeout_fut = tokio:: time:: timeout (
672
+ Duration :: from_secs ( BACKGROUND_TASK_SHUTDOWN_TIMEOUT_SECS ) ,
673
+ tasks. join_next_with_id ( ) ,
674
+ ) ;
675
+ match timeout_fut. await {
676
+ Ok ( Some ( Ok ( ( id, _) ) ) ) => {
677
+ log_trace ! ( self . logger, "Stopped background task with id {}" , id) ;
678
+ } ,
679
+ Ok ( Some ( Err ( e) ) ) => {
680
+ tasks. abort_all ( ) ;
681
+ log_trace ! ( self . logger, "Stopping background task failed: {}" , e) ;
682
+ break ;
683
+ } ,
684
+ Ok ( None ) => {
685
+ log_debug ! ( self . logger, "Stopped all background tasks" ) ;
686
+ break ;
687
+ } ,
688
+ Err ( e) => {
689
+ tasks. abort_all ( ) ;
690
+ log_error ! (
691
+ self . logger,
692
+ "Stopping background task timed out: {}" ,
693
+ e
694
+ ) ;
695
+ break ;
696
+ } ,
697
+ }
698
+ }
699
+ } )
700
+ } ) ;
701
+ }
702
+
646
703
// Wait until background processing stopped, at least until a timeout is reached.
647
704
if let Some ( background_processor_task) =
648
705
self . background_processor_task . lock ( ) . unwrap ( ) . take ( )
0 commit comments