Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 4 additions & 11 deletions src/builder.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -668,9 +668,9 @@ impl NodeBuilder {
let logger = setup_logger(&self.log_writer_config, &self.config)?;

let runtime = if let Some(handle) = self.runtime_handle.as_ref() {
Arc::new(Runtime::with_handle(handle.clone()))
Arc::new(Runtime::with_handle(handle.clone(), Arc::clone(&logger)))
} else {
Arc::new(Runtime::new().map_err(|e| {
Arc::new(Runtime::new(Arc::clone(&logger)).map_err(|e| {
log_error!(logger, "Failed to setup tokio runtime: {}", e);
BuildError::RuntimeSetupFailed
})?)
Expand DownExpand Up@@ -715,9 +715,9 @@ impl NodeBuilder {
let logger = setup_logger(&self.log_writer_config, &self.config)?;

let runtime = if let Some(handle) = self.runtime_handle.as_ref() {
Arc::new(Runtime::with_handle(handle.clone()))
Arc::new(Runtime::with_handle(handle.clone(), Arc::clone(&logger)))
} else {
Arc::new(Runtime::new().map_err(|e| {
Arc::new(Runtime::new(Arc::clone(&logger)).map_err(|e| {
log_error!(logger, "Failed to setup tokio runtime: {}", e);
BuildError::RuntimeSetupFailed
})?)
Expand DownExpand Up@@ -1668,18 +1668,11 @@ fn build_with_store_internal(
};

let (stop_sender, _) = tokio::sync::watch::channel(());
let background_processor_task = Mutex::new(None);
let background_tasks = Mutex::new(None);
let cancellable_background_tasks = Mutex::new(None);

let is_running = Arc::new(RwLock::new(false));

Ok(Node {
runtime,
stop_sender,
background_processor_task,
background_tasks,
cancellable_background_tasks,
config,
wallet,
chain_source,
Expand Down
4 changes: 2 additions & 2 deletions src/event.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -1059,7 +1059,7 @@ where
forwarding_channel_manager.process_pending_htlc_forwards();
};

self.runtime.spawn(future);
self.runtime.spawn_cancellable_background_task(future);
},
LdkEvent::SpendableOutputs { outputs, channel_id } => {
match self.output_sweeper.track_spendable_outputs(outputs, channel_id, true, None) {
Expand DownExpand Up@@ -1441,7 +1441,7 @@ where
}
}
};
self.runtime.spawn(future);
self.runtime.spawn_cancellable_background_task(future);
},
LdkEvent::BumpTransaction(bte) => {
match bte {
Expand Down
2 changes: 1 addition & 1 deletion src/gossip.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -144,6 +144,6 @@ impl RuntimeSpawner {

impl FutureSpawner for RuntimeSpawner {
fn spawn<T: Future<Output = ()> + Send + 'static>(&self, future: T) {
self.runtime.spawn(future);
self.runtime.spawn_cancellable_background_task(future);
}
}
186 changes: 36 additions & 150 deletions src/lib.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -128,9 +128,8 @@ pub use builder::NodeBuilder as Builder;

use chain::ChainSource;
use config::{
default_user_config, may_announce_channel, ChannelConfig, Config,
BACKGROUND_TASK_SHUTDOWN_TIMEOUT_SECS, LDK_EVENT_HANDLER_SHUTDOWN_TIMEOUT_SECS,
NODE_ANN_BCAST_INTERVAL, PEER_RECONNECTION_INTERVAL, RGS_SYNC_INTERVAL,
default_user_config, may_announce_channel, ChannelConfig, Config, NODE_ANN_BCAST_INTERVAL,
PEER_RECONNECTION_INTERVAL, RGS_SYNC_INTERVAL,
};
use connection::ConnectionManager;
use event::{EventHandler, EventQueue};
Expand DownExpand Up@@ -181,9 +180,6 @@ uniffi::include_scaffolding!("ldk_node");
pub struct Node {
runtime: Arc<Runtime>,
stop_sender: tokio::sync::watch::Sender<()>,
background_processor_task: Mutex<Option<tokio::task::JoinHandle<()>>>,
background_tasks: Mutex<Option<tokio::task::JoinSet<()>>>,
cancellable_background_tasks: Mutex<Option<tokio::task::JoinSet<()>>>,
config: Arc<Config>,
wallet: Arc<Wallet>,
chain_source: Arc<ChainSource>,
Expand DownExpand Up@@ -226,10 +222,6 @@ impl Node {
return Err(Error::AlreadyRunning);
}

let mut background_tasks = tokio::task::JoinSet::new();
let mut cancellable_background_tasks = tokio::task::JoinSet::new();
let runtime_handle = self.runtime.handle();

log_info!(
self.logger,
"Starting up LDK Node with node ID {} on network: {}",
Expand All@@ -253,27 +245,19 @@ impl Node {
let sync_cman = Arc::clone(&self.channel_manager);
let sync_cmon = Arc::clone(&self.chain_monitor);
let sync_sweeper = Arc::clone(&self.output_sweeper);
background_tasks.spawn_on(
async move {
chain_source
.continuously_sync_wallets(
stop_sync_receiver,
sync_cman,
sync_cmon,
sync_sweeper,
)
.await;
},
runtime_handle,
);
self.runtime.spawn_background_task(async move {
chain_source
.continuously_sync_wallets(stop_sync_receiver, sync_cman, sync_cmon, sync_sweeper)
.await;
});

if self.gossip_source.is_rgs() {
let gossip_source = Arc::clone(&self.gossip_source);
let gossip_sync_store = Arc::clone(&self.kv_store);
let gossip_sync_logger = Arc::clone(&self.logger);
let gossip_node_metrics = Arc::clone(&self.node_metrics);
let mut stop_gossip_sync = self.stop_sender.subscribe();
cancellable_background_tasks.spawn_on(async move {
self.runtime.spawn_cancellable_background_task(async move {
let mut interval = tokio::time::interval(RGS_SYNC_INTERVAL);
loop {
tokio::select! {
Expand DownExpand Up@@ -314,7 +298,7 @@ impl Node {
}
}
}
}, runtime_handle);
});
}

if let Some(listening_addresses) = &self.config.listening_addresses {
Expand All@@ -340,7 +324,7 @@ impl Node {
bind_addrs.extend(resolved_address);
}

cancellable_background_tasks.spawn_on(async move {
self.runtime.spawn_cancellable_background_task(async move {
{
let listener =
tokio::net::TcpListener::bind(&*bind_addrs).await
Expand DownExpand Up@@ -378,7 +362,7 @@ impl Node {
}

listening_indicator.store(false, Ordering::Release);
}, runtime_handle);
});
}

// Regularly reconnect to persisted peers.
Expand All@@ -387,7 +371,7 @@ impl Node {
let connect_logger = Arc::clone(&self.logger);
let connect_peer_store = Arc::clone(&self.peer_store);
let mut stop_connect = self.stop_sender.subscribe();
cancellable_background_tasks.spawn_on(async move {
self.runtime.spawn_cancellable_background_task(async move {
let mut interval = tokio::time::interval(PEER_RECONNECTION_INTERVAL);
interval.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Skip);
loop {
Expand DownExpand Up@@ -415,7 +399,7 @@ impl Node {
}
}
}
}, runtime_handle);
});

// Regularly broadcast node announcements.
let bcast_cm = Arc::clone(&self.channel_manager);
Expand All@@ -427,7 +411,7 @@ impl Node {
let mut stop_bcast = self.stop_sender.subscribe();
let node_alias = self.config.node_alias.clone();
if may_announce_channel(&self.config).is_ok() {
cancellable_background_tasks.spawn_on(async move {
self.runtime.spawn_cancellable_background_task(async move {
// We check every 30 secs whether our last broadcast is NODE_ANN_BCAST_INTERVAL away.
#[cfg(not(test))]
let mut interval = tokio::time::interval(Duration::from_secs(30));
Expand DownExpand Up@@ -498,15 +482,14 @@ impl Node {
}
}
}
}, runtime_handle);
});
}

let stop_tx_bcast = self.stop_sender.subscribe();
let chain_source = Arc::clone(&self.chain_source);
cancellable_background_tasks.spawn_on(
async move { chain_source.continuously_process_broadcast_queue(stop_tx_bcast).await },
runtime_handle,
);
self.runtime.spawn_cancellable_background_task(async move {
chain_source.continuously_process_broadcast_queue(stop_tx_bcast).await
});

let bump_tx_event_handler = Arc::new(BumpTransactionEventHandler::new(
Arc::clone(&self.tx_broadcaster),
Expand DownExpand Up@@ -563,7 +546,7 @@ impl Node {
})
};

let handle = self.runtime.spawn(async move {
self.runtime.spawn_background_processor_task(async move {
process_events_async(
background_persister,
|e| background_event_handler.handle_event(e),
Expand All@@ -584,38 +567,27 @@ impl Node {
panic!("Failed to process events");
});
});
debug_assert!(self.background_processor_task.lock().unwrap().is_none());
*self.background_processor_task.lock().unwrap() = Some(handle);

if let Some(liquidity_source) = self.liquidity_source.as_ref() {
let mut stop_liquidity_handler = self.stop_sender.subscribe();
let liquidity_handler = Arc::clone(&liquidity_source);
let liquidity_logger = Arc::clone(&self.logger);
background_tasks.spawn_on(
async move {
loop {
tokio::select! {
_ = stop_liquidity_handler.changed() => {
log_debug!(
liquidity_logger,
"Stopping processing liquidity events.",
);
return;
}
_ = liquidity_handler.handle_next_event() => {}
self.runtime.spawn_background_task(async move {
loop {
tokio::select! {
_ = stop_liquidity_handler.changed() => {
log_debug!(
liquidity_logger,
"Stopping processing liquidity events.",
);
return;
}
_ = liquidity_handler.handle_next_event() => {}
}
},
runtime_handle,
);
}
});
}

debug_assert!(self.background_tasks.lock().unwrap().is_none());
*self.background_tasks.lock().unwrap() = Some(background_tasks);

debug_assert!(self.cancellable_background_tasks.lock().unwrap().is_none());
*self.cancellable_background_tasks.lock().unwrap() = Some(cancellable_background_tasks);

log_info!(self.logger, "Startup complete.");
*is_running_lock = true;
Ok(())
Expand DownExpand Up@@ -649,15 +621,7 @@ impl Node {
}

// Cancel cancellable background tasks
if let Some(mut tasks) = self.cancellable_background_tasks.lock().unwrap().take() {
let runtime_handle = self.runtime.handle();
tasks.abort_all();
tokio::task::block_in_place(move || {
runtime_handle.block_on(async { while let Some(_) = tasks.join_next().await {} })
});
} else {
debug_assert!(false, "Expected some cancellable background tasks");
};
self.runtime.abort_cancellable_background_tasks();

// Disconnect all peers.
self.peer_manager.disconnect_all_peers();
Expand All@@ -668,91 +632,13 @@ impl Node {
log_debug!(self.logger, "Stopped chain sources.");

// Wait until non-cancellable background tasks (mod LDK's background processor) are done.
let runtime_handle = self.runtime.handle();
if let Some(mut tasks) = self.background_tasks.lock().unwrap().take() {
tokio::task::block_in_place(move || {
runtime_handle.block_on(async {
loop {
let timeout_fut = tokio::time::timeout(
Duration::from_secs(BACKGROUND_TASK_SHUTDOWN_TIMEOUT_SECS),
tasks.join_next_with_id(),
);
match timeout_fut.await {
Ok(Some(Ok((id, _)))) => {
log_trace!(self.logger, "Stopped background task with id {}", id);
},
Ok(Some(Err(e))) => {
tasks.abort_all();
log_trace!(self.logger, "Stopping background task failed: {}", e);
break;
},
Ok(None) => {
log_debug!(self.logger, "Stopped all background tasks");
break;
},
Err(e) => {
tasks.abort_all();
log_error!(
self.logger,
"Stopping background task timed out: {}",
e
);
break;
},
}
}
})
});
} else {
debug_assert!(false, "Expected some background tasks");
};
self.runtime.wait_on_background_tasks();

// Wait until background processing stopped, at least until a timeout is reached.
if let Some(background_processor_task) =
self.background_processor_task.lock().unwrap().take()
{
let abort_handle = background_processor_task.abort_handle();
let timeout_res = tokio::task::block_in_place(move || {
self.runtime.block_on(async {
tokio::time::timeout(
Duration::from_secs(LDK_EVENT_HANDLER_SHUTDOWN_TIMEOUT_SECS),
background_processor_task,
)
.await
})
});

match timeout_res {
Ok(stop_res) => match stop_res {
Ok(()) => log_debug!(self.logger, "Stopped background processing of events."),
Err(e) => {
abort_handle.abort();
log_error!(
self.logger,
"Stopping event handling failed. This should never happen: {}",
e
);
panic!("Stopping event handling failed. This should never happen.");
},
},
Err(e) => {
abort_handle.abort();
log_error!(self.logger, "Stopping event handling timed out: {}", e);
},
}
} else {
debug_assert!(false, "Expected a background processing task");
};
// Finally, wait until background processing stopped, at least until a timeout is reached.
self.runtime.wait_on_background_processor_task();

#[cfg(tokio_unstable)]
{
let runtime_handle = self.runtime.handle();
log_trace!(
self.logger,
"Active runtime tasks left prior to shutdown: {}",
runtime_handle.metrics().active_tasks_count()
);
}
self.runtime.log_metrics();

log_info!(self.logger, "Shutdown complete.");
*is_running_lock = false;
Expand Down
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 4 additions & 11 deletions src/builder.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -668,9 +668,9 @@ impl NodeBuilder {
let logger = setup_logger(&self.log_writer_config, &self.config)?;

let runtime = if let Some(handle) = self.runtime_handle.as_ref() {
Arc::new(Runtime::with_handle(handle.clone()))
Arc::new(Runtime::with_handle(handle.clone(), Arc::clone(&logger)))
} else {
Arc::new(Runtime::new().map_err(|e| {
Arc::new(Runtime::new(Arc::clone(&logger)).map_err(|e| {
log_error!(logger, "Failed to setup tokio runtime: {}", e);
BuildError::RuntimeSetupFailed
})?)
Expand DownExpand Up@@ -715,9 +715,9 @@ impl NodeBuilder {
let logger = setup_logger(&self.log_writer_config, &self.config)?;

let runtime = if let Some(handle) = self.runtime_handle.as_ref() {
Arc::new(Runtime::with_handle(handle.clone()))
Arc::new(Runtime::with_handle(handle.clone(), Arc::clone(&logger)))
} else {
Arc::new(Runtime::new().map_err(|e| {
Arc::new(Runtime::new(Arc::clone(&logger)).map_err(|e| {
log_error!(logger, "Failed to setup tokio runtime: {}", e);
BuildError::RuntimeSetupFailed
})?)
Expand DownExpand Up@@ -1668,18 +1668,11 @@ fn build_with_store_internal(
};

let (stop_sender, _) = tokio::sync::watch::channel(());
let background_processor_task = Mutex::new(None);
let background_tasks = Mutex::new(None);
let cancellable_background_tasks = Mutex::new(None);

let is_running = Arc::new(RwLock::new(false));

Ok(Node {
runtime,
stop_sender,
background_processor_task,
background_tasks,
cancellable_background_tasks,
config,
wallet,
chain_source,
Expand Down
4 changes: 2 additions & 2 deletions src/event.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -1059,7 +1059,7 @@ where
forwarding_channel_manager.process_pending_htlc_forwards();
};

self.runtime.spawn(future);
self.runtime.spawn_cancellable_background_task(future);
},
LdkEvent::SpendableOutputs { outputs, channel_id } => {
match self.output_sweeper.track_spendable_outputs(outputs, channel_id, true, None) {
Expand DownExpand Up@@ -1441,7 +1441,7 @@ where
}
}
};
self.runtime.spawn(future);
self.runtime.spawn_cancellable_background_task(future);
},
LdkEvent::BumpTransaction(bte) => {
match bte {
Expand Down
2 changes: 1 addition & 1 deletion src/gossip.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -144,6 +144,6 @@ impl RuntimeSpawner {

impl FutureSpawner for RuntimeSpawner {
fn spawn<T: Future<Output = ()> + Send + 'static>(&self, future: T) {
self.runtime.spawn(future);
self.runtime.spawn_cancellable_background_task(future);
}
}
186 changes: 36 additions & 150 deletions src/lib.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -128,9 +128,8 @@ pub use builder::NodeBuilder as Builder;

use chain::ChainSource;
use config::{
default_user_config, may_announce_channel, ChannelConfig, Config,
BACKGROUND_TASK_SHUTDOWN_TIMEOUT_SECS, LDK_EVENT_HANDLER_SHUTDOWN_TIMEOUT_SECS,
NODE_ANN_BCAST_INTERVAL, PEER_RECONNECTION_INTERVAL, RGS_SYNC_INTERVAL,
default_user_config, may_announce_channel, ChannelConfig, Config, NODE_ANN_BCAST_INTERVAL,
PEER_RECONNECTION_INTERVAL, RGS_SYNC_INTERVAL,
};
use connection::ConnectionManager;
use event::{EventHandler, EventQueue};
Expand DownExpand Up@@ -181,9 +180,6 @@ uniffi::include_scaffolding!("ldk_node");
pub struct Node {
runtime: Arc<Runtime>,
stop_sender: tokio::sync::watch::Sender<()>,
background_processor_task: Mutex<Option<tokio::task::JoinHandle<()>>>,
background_tasks: Mutex<Option<tokio::task::JoinSet<()>>>,
cancellable_background_tasks: Mutex<Option<tokio::task::JoinSet<()>>>,
config: Arc<Config>,
wallet: Arc<Wallet>,
chain_source: Arc<ChainSource>,
Expand DownExpand Up@@ -226,10 +222,6 @@ impl Node {
return Err(Error::AlreadyRunning);
}

let mut background_tasks = tokio::task::JoinSet::new();
let mut cancellable_background_tasks = tokio::task::JoinSet::new();
let runtime_handle = self.runtime.handle();

log_info!(
self.logger,
"Starting up LDK Node with node ID {} on network: {}",
Expand All@@ -253,27 +245,19 @@ impl Node {
let sync_cman = Arc::clone(&self.channel_manager);
let sync_cmon = Arc::clone(&self.chain_monitor);
let sync_sweeper = Arc::clone(&self.output_sweeper);
background_tasks.spawn_on(
async move {
chain_source
.continuously_sync_wallets(
stop_sync_receiver,
sync_cman,
sync_cmon,
sync_sweeper,
)
.await;
},
runtime_handle,
);
self.runtime.spawn_background_task(async move {
chain_source
.continuously_sync_wallets(stop_sync_receiver, sync_cman, sync_cmon, sync_sweeper)
.await;
});

if self.gossip_source.is_rgs() {
let gossip_source = Arc::clone(&self.gossip_source);
let gossip_sync_store = Arc::clone(&self.kv_store);
let gossip_sync_logger = Arc::clone(&self.logger);
let gossip_node_metrics = Arc::clone(&self.node_metrics);
let mut stop_gossip_sync = self.stop_sender.subscribe();
cancellable_background_tasks.spawn_on(async move {
self.runtime.spawn_cancellable_background_task(async move {
let mut interval = tokio::time::interval(RGS_SYNC_INTERVAL);
loop {
tokio::select! {
Expand DownExpand Up@@ -314,7 +298,7 @@ impl Node {
}
}
}
}, runtime_handle);
});
}

if let Some(listening_addresses) = &self.config.listening_addresses {
Expand All@@ -340,7 +324,7 @@ impl Node {
bind_addrs.extend(resolved_address);
}

cancellable_background_tasks.spawn_on(async move {
self.runtime.spawn_cancellable_background_task(async move {
{
let listener =
tokio::net::TcpListener::bind(&*bind_addrs).await
Expand DownExpand Up@@ -378,7 +362,7 @@ impl Node {
}

listening_indicator.store(false, Ordering::Release);
}, runtime_handle);
});
}

// Regularly reconnect to persisted peers.
Expand All@@ -387,7 +371,7 @@ impl Node {
let connect_logger = Arc::clone(&self.logger);
let connect_peer_store = Arc::clone(&self.peer_store);
let mut stop_connect = self.stop_sender.subscribe();
cancellable_background_tasks.spawn_on(async move {
self.runtime.spawn_cancellable_background_task(async move {
let mut interval = tokio::time::interval(PEER_RECONNECTION_INTERVAL);
interval.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Skip);
loop {
Expand DownExpand Up@@ -415,7 +399,7 @@ impl Node {
}
}
}
}, runtime_handle);
});

// Regularly broadcast node announcements.
let bcast_cm = Arc::clone(&self.channel_manager);
Expand All@@ -427,7 +411,7 @@ impl Node {
let mut stop_bcast = self.stop_sender.subscribe();
let node_alias = self.config.node_alias.clone();
if may_announce_channel(&self.config).is_ok() {
cancellable_background_tasks.spawn_on(async move {
self.runtime.spawn_cancellable_background_task(async move {
// We check every 30 secs whether our last broadcast is NODE_ANN_BCAST_INTERVAL away.
#[cfg(not(test))]
let mut interval = tokio::time::interval(Duration::from_secs(30));
Expand DownExpand Up@@ -498,15 +482,14 @@ impl Node {
}
}
}
}, runtime_handle);
});
}

let stop_tx_bcast = self.stop_sender.subscribe();
let chain_source = Arc::clone(&self.chain_source);
cancellable_background_tasks.spawn_on(
async move { chain_source.continuously_process_broadcast_queue(stop_tx_bcast).await },
runtime_handle,
);
self.runtime.spawn_cancellable_background_task(async move {
chain_source.continuously_process_broadcast_queue(stop_tx_bcast).await
});

let bump_tx_event_handler = Arc::new(BumpTransactionEventHandler::new(
Arc::clone(&self.tx_broadcaster),
Expand DownExpand Up@@ -563,7 +546,7 @@ impl Node {
})
};

let handle = self.runtime.spawn(async move {
self.runtime.spawn_background_processor_task(async move {
process_events_async(
background_persister,
|e| background_event_handler.handle_event(e),
Expand All@@ -584,38 +567,27 @@ impl Node {
panic!("Failed to process events");
});
});
debug_assert!(self.background_processor_task.lock().unwrap().is_none());
*self.background_processor_task.lock().unwrap() = Some(handle);

if let Some(liquidity_source) = self.liquidity_source.as_ref() {
let mut stop_liquidity_handler = self.stop_sender.subscribe();
let liquidity_handler = Arc::clone(&liquidity_source);
let liquidity_logger = Arc::clone(&self.logger);
background_tasks.spawn_on(
async move {
loop {
tokio::select! {
_ = stop_liquidity_handler.changed() => {
log_debug!(
liquidity_logger,
"Stopping processing liquidity events.",
);
return;
}
_ = liquidity_handler.handle_next_event() => {}
self.runtime.spawn_background_task(async move {
loop {
tokio::select! {
_ = stop_liquidity_handler.changed() => {
log_debug!(
liquidity_logger,
"Stopping processing liquidity events.",
);
return;
}
_ = liquidity_handler.handle_next_event() => {}
}
},
runtime_handle,
);
}
});
}

debug_assert!(self.background_tasks.lock().unwrap().is_none());
*self.background_tasks.lock().unwrap() = Some(background_tasks);

debug_assert!(self.cancellable_background_tasks.lock().unwrap().is_none());
*self.cancellable_background_tasks.lock().unwrap() = Some(cancellable_background_tasks);

log_info!(self.logger, "Startup complete.");
*is_running_lock = true;
Ok(())
Expand DownExpand Up@@ -649,15 +621,7 @@ impl Node {
}

// Cancel cancellable background tasks
if let Some(mut tasks) = self.cancellable_background_tasks.lock().unwrap().take() {
let runtime_handle = self.runtime.handle();
tasks.abort_all();
tokio::task::block_in_place(move || {
runtime_handle.block_on(async { while let Some(_) = tasks.join_next().await {} })
});
} else {
debug_assert!(false, "Expected some cancellable background tasks");
};
self.runtime.abort_cancellable_background_tasks();

// Disconnect all peers.
self.peer_manager.disconnect_all_peers();
Expand All@@ -668,91 +632,13 @@ impl Node {
log_debug!(self.logger, "Stopped chain sources.");

// Wait until non-cancellable background tasks (mod LDK's background processor) are done.
let runtime_handle = self.runtime.handle();
if let Some(mut tasks) = self.background_tasks.lock().unwrap().take() {
tokio::task::block_in_place(move || {
runtime_handle.block_on(async {
loop {
let timeout_fut = tokio::time::timeout(
Duration::from_secs(BACKGROUND_TASK_SHUTDOWN_TIMEOUT_SECS),
tasks.join_next_with_id(),
);
match timeout_fut.await {
Ok(Some(Ok((id, _)))) => {
log_trace!(self.logger, "Stopped background task with id {}", id);
},
Ok(Some(Err(e))) => {
tasks.abort_all();
log_trace!(self.logger, "Stopping background task failed: {}", e);
break;
},
Ok(None) => {
log_debug!(self.logger, "Stopped all background tasks");
break;
},
Err(e) => {
tasks.abort_all();
log_error!(
self.logger,
"Stopping background task timed out: {}",
e
);
break;
},
}
}
})
});
} else {
debug_assert!(false, "Expected some background tasks");
};
self.runtime.wait_on_background_tasks();

// Wait until background processing stopped, at least until a timeout is reached.
if let Some(background_processor_task) =
self.background_processor_task.lock().unwrap().take()
{
let abort_handle = background_processor_task.abort_handle();
let timeout_res = tokio::task::block_in_place(move || {
self.runtime.block_on(async {
tokio::time::timeout(
Duration::from_secs(LDK_EVENT_HANDLER_SHUTDOWN_TIMEOUT_SECS),
background_processor_task,
)
.await
})
});

match timeout_res {
Ok(stop_res) => match stop_res {
Ok(()) => log_debug!(self.logger, "Stopped background processing of events."),
Err(e) => {
abort_handle.abort();
log_error!(
self.logger,
"Stopping event handling failed. This should never happen: {}",
e
);
panic!("Stopping event handling failed. This should never happen.");
},
},
Err(e) => {
abort_handle.abort();
log_error!(self.logger, "Stopping event handling timed out: {}", e);
},
}
} else {
debug_assert!(false, "Expected a background processing task");
};
// Finally, wait until background processing stopped, at least until a timeout is reached.
self.runtime.wait_on_background_processor_task();

#[cfg(tokio_unstable)]
{
let runtime_handle = self.runtime.handle();
log_trace!(
self.logger,
"Active runtime tasks left prior to shutdown: {}",
runtime_handle.metrics().active_tasks_count()
);
}
self.runtime.log_metrics();

log_info!(self.logger, "Shutdown complete.");
*is_running_lock = false;
Expand Down
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 4 additions & 11 deletions src/builder.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -668,9 +668,9 @@ impl NodeBuilder {
let logger = setup_logger(&self.log_writer_config, &self.config)?;

let runtime = if let Some(handle) = self.runtime_handle.as_ref() {
Arc::new(Runtime::with_handle(handle.clone()))
Arc::new(Runtime::with_handle(handle.clone(), Arc::clone(&logger)))
} else {
Arc::new(Runtime::new().map_err(|e| {
Arc::new(Runtime::new(Arc::clone(&logger)).map_err(|e| {
log_error!(logger, "Failed to setup tokio runtime: {}", e);
BuildError::RuntimeSetupFailed
})?)
Expand DownExpand Up@@ -715,9 +715,9 @@ impl NodeBuilder {
let logger = setup_logger(&self.log_writer_config, &self.config)?;

let runtime = if let Some(handle) = self.runtime_handle.as_ref() {
Arc::new(Runtime::with_handle(handle.clone()))
Arc::new(Runtime::with_handle(handle.clone(), Arc::clone(&logger)))
} else {
Arc::new(Runtime::new().map_err(|e| {
Arc::new(Runtime::new(Arc::clone(&logger)).map_err(|e| {
log_error!(logger, "Failed to setup tokio runtime: {}", e);
BuildError::RuntimeSetupFailed
})?)
Expand DownExpand Up@@ -1668,18 +1668,11 @@ fn build_with_store_internal(
};

let (stop_sender, _) = tokio::sync::watch::channel(());
let background_processor_task = Mutex::new(None);
let background_tasks = Mutex::new(None);
let cancellable_background_tasks = Mutex::new(None);

let is_running = Arc::new(RwLock::new(false));

Ok(Node {
runtime,
stop_sender,
background_processor_task,
background_tasks,
cancellable_background_tasks,
config,
wallet,
chain_source,
Expand Down
4 changes: 2 additions & 2 deletions src/event.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -1059,7 +1059,7 @@ where
forwarding_channel_manager.process_pending_htlc_forwards();
};

self.runtime.spawn(future);
self.runtime.spawn_cancellable_background_task(future);
},
LdkEvent::SpendableOutputs { outputs, channel_id } => {
match self.output_sweeper.track_spendable_outputs(outputs, channel_id, true, None) {
Expand DownExpand Up@@ -1441,7 +1441,7 @@ where
}
}
};
self.runtime.spawn(future);
self.runtime.spawn_cancellable_background_task(future);
},
LdkEvent::BumpTransaction(bte) => {
match bte {
Expand Down
2 changes: 1 addition & 1 deletion src/gossip.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -144,6 +144,6 @@ impl RuntimeSpawner {

impl FutureSpawner for RuntimeSpawner {
fn spawn<T: Future<Output = ()> + Send + 'static>(&self, future: T) {
self.runtime.spawn(future);
self.runtime.spawn_cancellable_background_task(future);
}
}
186 changes: 36 additions & 150 deletions src/lib.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -128,9 +128,8 @@ pub use builder::NodeBuilder as Builder;

use chain::ChainSource;
use config::{
default_user_config, may_announce_channel, ChannelConfig, Config,
BACKGROUND_TASK_SHUTDOWN_TIMEOUT_SECS, LDK_EVENT_HANDLER_SHUTDOWN_TIMEOUT_SECS,
NODE_ANN_BCAST_INTERVAL, PEER_RECONNECTION_INTERVAL, RGS_SYNC_INTERVAL,
default_user_config, may_announce_channel, ChannelConfig, Config, NODE_ANN_BCAST_INTERVAL,
PEER_RECONNECTION_INTERVAL, RGS_SYNC_INTERVAL,
};
use connection::ConnectionManager;
use event::{EventHandler, EventQueue};
Expand DownExpand Up@@ -181,9 +180,6 @@ uniffi::include_scaffolding!("ldk_node");
pub struct Node {
runtime: Arc<Runtime>,
stop_sender: tokio::sync::watch::Sender<()>,
background_processor_task: Mutex<Option<tokio::task::JoinHandle<()>>>,
background_tasks: Mutex<Option<tokio::task::JoinSet<()>>>,
cancellable_background_tasks: Mutex<Option<tokio::task::JoinSet<()>>>,
config: Arc<Config>,
wallet: Arc<Wallet>,
chain_source: Arc<ChainSource>,
Expand DownExpand Up@@ -226,10 +222,6 @@ impl Node {
return Err(Error::AlreadyRunning);
}

let mut background_tasks = tokio::task::JoinSet::new();
let mut cancellable_background_tasks = tokio::task::JoinSet::new();
let runtime_handle = self.runtime.handle();

log_info!(
self.logger,
"Starting up LDK Node with node ID {} on network: {}",
Expand All@@ -253,27 +245,19 @@ impl Node {
let sync_cman = Arc::clone(&self.channel_manager);
let sync_cmon = Arc::clone(&self.chain_monitor);
let sync_sweeper = Arc::clone(&self.output_sweeper);
background_tasks.spawn_on(
async move {
chain_source
.continuously_sync_wallets(
stop_sync_receiver,
sync_cman,
sync_cmon,
sync_sweeper,
)
.await;
},
runtime_handle,
);
self.runtime.spawn_background_task(async move {
chain_source
.continuously_sync_wallets(stop_sync_receiver, sync_cman, sync_cmon, sync_sweeper)
.await;
});

if self.gossip_source.is_rgs() {
let gossip_source = Arc::clone(&self.gossip_source);
let gossip_sync_store = Arc::clone(&self.kv_store);
let gossip_sync_logger = Arc::clone(&self.logger);
let gossip_node_metrics = Arc::clone(&self.node_metrics);
let mut stop_gossip_sync = self.stop_sender.subscribe();
cancellable_background_tasks.spawn_on(async move {
self.runtime.spawn_cancellable_background_task(async move {
let mut interval = tokio::time::interval(RGS_SYNC_INTERVAL);
loop {
tokio::select! {
Expand DownExpand Up@@ -314,7 +298,7 @@ impl Node {
}
}
}
}, runtime_handle);
});
}

if let Some(listening_addresses) = &self.config.listening_addresses {
Expand All@@ -340,7 +324,7 @@ impl Node {
bind_addrs.extend(resolved_address);
}

cancellable_background_tasks.spawn_on(async move {
self.runtime.spawn_cancellable_background_task(async move {
{
let listener =
tokio::net::TcpListener::bind(&*bind_addrs).await
Expand DownExpand Up@@ -378,7 +362,7 @@ impl Node {
}

listening_indicator.store(false, Ordering::Release);
}, runtime_handle);
});
}

// Regularly reconnect to persisted peers.
Expand All@@ -387,7 +371,7 @@ impl Node {
let connect_logger = Arc::clone(&self.logger);
let connect_peer_store = Arc::clone(&self.peer_store);
let mut stop_connect = self.stop_sender.subscribe();
cancellable_background_tasks.spawn_on(async move {
self.runtime.spawn_cancellable_background_task(async move {
let mut interval = tokio::time::interval(PEER_RECONNECTION_INTERVAL);
interval.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Skip);
loop {
Expand DownExpand Up@@ -415,7 +399,7 @@ impl Node {
}
}
}
}, runtime_handle);
});

// Regularly broadcast node announcements.
let bcast_cm = Arc::clone(&self.channel_manager);
Expand All@@ -427,7 +411,7 @@ impl Node {
let mut stop_bcast = self.stop_sender.subscribe();
let node_alias = self.config.node_alias.clone();
if may_announce_channel(&self.config).is_ok() {
cancellable_background_tasks.spawn_on(async move {
self.runtime.spawn_cancellable_background_task(async move {
// We check every 30 secs whether our last broadcast is NODE_ANN_BCAST_INTERVAL away.
#[cfg(not(test))]
let mut interval = tokio::time::interval(Duration::from_secs(30));
Expand DownExpand Up@@ -498,15 +482,14 @@ impl Node {
}
}
}
}, runtime_handle);
});
}

let stop_tx_bcast = self.stop_sender.subscribe();
let chain_source = Arc::clone(&self.chain_source);
cancellable_background_tasks.spawn_on(
async move { chain_source.continuously_process_broadcast_queue(stop_tx_bcast).await },
runtime_handle,
);
self.runtime.spawn_cancellable_background_task(async move {
chain_source.continuously_process_broadcast_queue(stop_tx_bcast).await
});

let bump_tx_event_handler = Arc::new(BumpTransactionEventHandler::new(
Arc::clone(&self.tx_broadcaster),
Expand DownExpand Up@@ -563,7 +546,7 @@ impl Node {
})
};

let handle = self.runtime.spawn(async move {
self.runtime.spawn_background_processor_task(async move {
process_events_async(
background_persister,
|e| background_event_handler.handle_event(e),
Expand All@@ -584,38 +567,27 @@ impl Node {
panic!("Failed to process events");
});
});
debug_assert!(self.background_processor_task.lock().unwrap().is_none());
*self.background_processor_task.lock().unwrap() = Some(handle);

if let Some(liquidity_source) = self.liquidity_source.as_ref() {
let mut stop_liquidity_handler = self.stop_sender.subscribe();
let liquidity_handler = Arc::clone(&liquidity_source);
let liquidity_logger = Arc::clone(&self.logger);
background_tasks.spawn_on(
async move {
loop {
tokio::select! {
_ = stop_liquidity_handler.changed() => {
log_debug!(
liquidity_logger,
"Stopping processing liquidity events.",
);
return;
}
_ = liquidity_handler.handle_next_event() => {}
self.runtime.spawn_background_task(async move {
loop {
tokio::select! {
_ = stop_liquidity_handler.changed() => {
log_debug!(
liquidity_logger,
"Stopping processing liquidity events.",
);
return;
}
_ = liquidity_handler.handle_next_event() => {}
}
},
runtime_handle,
);
}
});
}

debug_assert!(self.background_tasks.lock().unwrap().is_none());
*self.background_tasks.lock().unwrap() = Some(background_tasks);

debug_assert!(self.cancellable_background_tasks.lock().unwrap().is_none());
*self.cancellable_background_tasks.lock().unwrap() = Some(cancellable_background_tasks);

log_info!(self.logger, "Startup complete.");
*is_running_lock = true;
Ok(())
Expand DownExpand Up@@ -649,15 +621,7 @@ impl Node {
}

// Cancel cancellable background tasks
if let Some(mut tasks) = self.cancellable_background_tasks.lock().unwrap().take() {
let runtime_handle = self.runtime.handle();
tasks.abort_all();
tokio::task::block_in_place(move || {
runtime_handle.block_on(async { while let Some(_) = tasks.join_next().await {} })
});
} else {
debug_assert!(false, "Expected some cancellable background tasks");
};
self.runtime.abort_cancellable_background_tasks();

// Disconnect all peers.
self.peer_manager.disconnect_all_peers();
Expand All@@ -668,91 +632,13 @@ impl Node {
log_debug!(self.logger, "Stopped chain sources.");

// Wait until non-cancellable background tasks (mod LDK's background processor) are done.
let runtime_handle = self.runtime.handle();
if let Some(mut tasks) = self.background_tasks.lock().unwrap().take() {
tokio::task::block_in_place(move || {
runtime_handle.block_on(async {
loop {
let timeout_fut = tokio::time::timeout(
Duration::from_secs(BACKGROUND_TASK_SHUTDOWN_TIMEOUT_SECS),
tasks.join_next_with_id(),
);
match timeout_fut.await {
Ok(Some(Ok((id, _)))) => {
log_trace!(self.logger, "Stopped background task with id {}", id);
},
Ok(Some(Err(e))) => {
tasks.abort_all();
log_trace!(self.logger, "Stopping background task failed: {}", e);
break;
},
Ok(None) => {
log_debug!(self.logger, "Stopped all background tasks");
break;
},
Err(e) => {
tasks.abort_all();
log_error!(
self.logger,
"Stopping background task timed out: {}",
e
);
break;
},
}
}
})
});
} else {
debug_assert!(false, "Expected some background tasks");
};
self.runtime.wait_on_background_tasks();

// Wait until background processing stopped, at least until a timeout is reached.
if let Some(background_processor_task) =
self.background_processor_task.lock().unwrap().take()
{
let abort_handle = background_processor_task.abort_handle();
let timeout_res = tokio::task::block_in_place(move || {
self.runtime.block_on(async {
tokio::time::timeout(
Duration::from_secs(LDK_EVENT_HANDLER_SHUTDOWN_TIMEOUT_SECS),
background_processor_task,
)
.await
})
});

match timeout_res {
Ok(stop_res) => match stop_res {
Ok(()) => log_debug!(self.logger, "Stopped background processing of events."),
Err(e) => {
abort_handle.abort();
log_error!(
self.logger,
"Stopping event handling failed. This should never happen: {}",
e
);
panic!("Stopping event handling failed. This should never happen.");
},
},
Err(e) => {
abort_handle.abort();
log_error!(self.logger, "Stopping event handling timed out: {}", e);
},
}
} else {
debug_assert!(false, "Expected a background processing task");
};
// Finally, wait until background processing stopped, at least until a timeout is reached.
self.runtime.wait_on_background_processor_task();

#[cfg(tokio_unstable)]
{
let runtime_handle = self.runtime.handle();
log_trace!(
self.logger,
"Active runtime tasks left prior to shutdown: {}",
runtime_handle.metrics().active_tasks_count()
);
}
self.runtime.log_metrics();

log_info!(self.logger, "Shutdown complete.");
*is_running_lock = false;
Expand Down
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 4 additions & 11 deletions src/builder.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -668,9 +668,9 @@ impl NodeBuilder {
let logger = setup_logger(&self.log_writer_config, &self.config)?;

let runtime = if let Some(handle) = self.runtime_handle.as_ref() {
Arc::new(Runtime::with_handle(handle.clone()))
Arc::new(Runtime::with_handle(handle.clone(), Arc::clone(&logger)))
} else {
Arc::new(Runtime::new().map_err(|e| {
Arc::new(Runtime::new(Arc::clone(&logger)).map_err(|e| {
log_error!(logger, "Failed to setup tokio runtime: {}", e);
BuildError::RuntimeSetupFailed
})?)
Expand DownExpand Up@@ -715,9 +715,9 @@ impl NodeBuilder {
let logger = setup_logger(&self.log_writer_config, &self.config)?;

let runtime = if let Some(handle) = self.runtime_handle.as_ref() {
Arc::new(Runtime::with_handle(handle.clone()))
Arc::new(Runtime::with_handle(handle.clone(), Arc::clone(&logger)))
} else {
Arc::new(Runtime::new().map_err(|e| {
Arc::new(Runtime::new(Arc::clone(&logger)).map_err(|e| {
log_error!(logger, "Failed to setup tokio runtime: {}", e);
BuildError::RuntimeSetupFailed
})?)
Expand DownExpand Up@@ -1668,18 +1668,11 @@ fn build_with_store_internal(
};

let (stop_sender, _) = tokio::sync::watch::channel(());
let background_processor_task = Mutex::new(None);
let background_tasks = Mutex::new(None);
let cancellable_background_tasks = Mutex::new(None);

let is_running = Arc::new(RwLock::new(false));

Ok(Node {
runtime,
stop_sender,
background_processor_task,
background_tasks,
cancellable_background_tasks,
config,
wallet,
chain_source,
Expand Down
4 changes: 2 additions & 2 deletions src/event.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -1059,7 +1059,7 @@ where
forwarding_channel_manager.process_pending_htlc_forwards();
};

self.runtime.spawn(future);
self.runtime.spawn_cancellable_background_task(future);
},
LdkEvent::SpendableOutputs { outputs, channel_id } => {
match self.output_sweeper.track_spendable_outputs(outputs, channel_id, true, None) {
Expand DownExpand Up@@ -1441,7 +1441,7 @@ where
}
}
};
self.runtime.spawn(future);
self.runtime.spawn_cancellable_background_task(future);
},
LdkEvent::BumpTransaction(bte) => {
match bte {
Expand Down
2 changes: 1 addition & 1 deletion src/gossip.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -144,6 +144,6 @@ impl RuntimeSpawner {

impl FutureSpawner for RuntimeSpawner {
fn spawn<T: Future<Output = ()> + Send + 'static>(&self, future: T) {
self.runtime.spawn(future);
self.runtime.spawn_cancellable_background_task(future);
}
}
186 changes: 36 additions & 150 deletions src/lib.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -128,9 +128,8 @@ pub use builder::NodeBuilder as Builder;

use chain::ChainSource;
use config::{
default_user_config, may_announce_channel, ChannelConfig, Config,
BACKGROUND_TASK_SHUTDOWN_TIMEOUT_SECS, LDK_EVENT_HANDLER_SHUTDOWN_TIMEOUT_SECS,
NODE_ANN_BCAST_INTERVAL, PEER_RECONNECTION_INTERVAL, RGS_SYNC_INTERVAL,
default_user_config, may_announce_channel, ChannelConfig, Config, NODE_ANN_BCAST_INTERVAL,
PEER_RECONNECTION_INTERVAL, RGS_SYNC_INTERVAL,
};
use connection::ConnectionManager;
use event::{EventHandler, EventQueue};
Expand DownExpand Up@@ -181,9 +180,6 @@ uniffi::include_scaffolding!("ldk_node");
pub struct Node {
runtime: Arc<Runtime>,
stop_sender: tokio::sync::watch::Sender<()>,
background_processor_task: Mutex<Option<tokio::task::JoinHandle<()>>>,
background_tasks: Mutex<Option<tokio::task::JoinSet<()>>>,
cancellable_background_tasks: Mutex<Option<tokio::task::JoinSet<()>>>,
config: Arc<Config>,
wallet: Arc<Wallet>,
chain_source: Arc<ChainSource>,
Expand DownExpand Up@@ -226,10 +222,6 @@ impl Node {
return Err(Error::AlreadyRunning);
}

let mut background_tasks = tokio::task::JoinSet::new();
let mut cancellable_background_tasks = tokio::task::JoinSet::new();
let runtime_handle = self.runtime.handle();

log_info!(
self.logger,
"Starting up LDK Node with node ID {} on network: {}",
Expand All@@ -253,27 +245,19 @@ impl Node {
let sync_cman = Arc::clone(&self.channel_manager);
let sync_cmon = Arc::clone(&self.chain_monitor);
let sync_sweeper = Arc::clone(&self.output_sweeper);
background_tasks.spawn_on(
async move {
chain_source
.continuously_sync_wallets(
stop_sync_receiver,
sync_cman,
sync_cmon,
sync_sweeper,
)
.await;
},
runtime_handle,
);
self.runtime.spawn_background_task(async move {
chain_source
.continuously_sync_wallets(stop_sync_receiver, sync_cman, sync_cmon, sync_sweeper)
.await;
});

if self.gossip_source.is_rgs() {
let gossip_source = Arc::clone(&self.gossip_source);
let gossip_sync_store = Arc::clone(&self.kv_store);
let gossip_sync_logger = Arc::clone(&self.logger);
let gossip_node_metrics = Arc::clone(&self.node_metrics);
let mut stop_gossip_sync = self.stop_sender.subscribe();
cancellable_background_tasks.spawn_on(async move {
self.runtime.spawn_cancellable_background_task(async move {
let mut interval = tokio::time::interval(RGS_SYNC_INTERVAL);
loop {
tokio::select! {
Expand DownExpand Up@@ -314,7 +298,7 @@ impl Node {
}
}
}
}, runtime_handle);
});
}

if let Some(listening_addresses) = &self.config.listening_addresses {
Expand All@@ -340,7 +324,7 @@ impl Node {
bind_addrs.extend(resolved_address);
}

cancellable_background_tasks.spawn_on(async move {
self.runtime.spawn_cancellable_background_task(async move {
{
let listener =
tokio::net::TcpListener::bind(&*bind_addrs).await
Expand DownExpand Up@@ -378,7 +362,7 @@ impl Node {
}

listening_indicator.store(false, Ordering::Release);
}, runtime_handle);
});
}

// Regularly reconnect to persisted peers.
Expand All@@ -387,7 +371,7 @@ impl Node {
let connect_logger = Arc::clone(&self.logger);
let connect_peer_store = Arc::clone(&self.peer_store);
let mut stop_connect = self.stop_sender.subscribe();
cancellable_background_tasks.spawn_on(async move {
self.runtime.spawn_cancellable_background_task(async move {
let mut interval = tokio::time::interval(PEER_RECONNECTION_INTERVAL);
interval.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Skip);
loop {
Expand DownExpand Up@@ -415,7 +399,7 @@ impl Node {
}
}
}
}, runtime_handle);
});

// Regularly broadcast node announcements.
let bcast_cm = Arc::clone(&self.channel_manager);
Expand All@@ -427,7 +411,7 @@ impl Node {
let mut stop_bcast = self.stop_sender.subscribe();
let node_alias = self.config.node_alias.clone();
if may_announce_channel(&self.config).is_ok() {
cancellable_background_tasks.spawn_on(async move {
self.runtime.spawn_cancellable_background_task(async move {
// We check every 30 secs whether our last broadcast is NODE_ANN_BCAST_INTERVAL away.
#[cfg(not(test))]
let mut interval = tokio::time::interval(Duration::from_secs(30));
Expand DownExpand Up@@ -498,15 +482,14 @@ impl Node {
}
}
}
}, runtime_handle);
});
}

let stop_tx_bcast = self.stop_sender.subscribe();
let chain_source = Arc::clone(&self.chain_source);
cancellable_background_tasks.spawn_on(
async move { chain_source.continuously_process_broadcast_queue(stop_tx_bcast).await },
runtime_handle,
);
self.runtime.spawn_cancellable_background_task(async move {
chain_source.continuously_process_broadcast_queue(stop_tx_bcast).await
});

let bump_tx_event_handler = Arc::new(BumpTransactionEventHandler::new(
Arc::clone(&self.tx_broadcaster),
Expand DownExpand Up@@ -563,7 +546,7 @@ impl Node {
})
};

let handle = self.runtime.spawn(async move {
self.runtime.spawn_background_processor_task(async move {
process_events_async(
background_persister,
|e| background_event_handler.handle_event(e),
Expand All@@ -584,38 +567,27 @@ impl Node {
panic!("Failed to process events");
});
});
debug_assert!(self.background_processor_task.lock().unwrap().is_none());
*self.background_processor_task.lock().unwrap() = Some(handle);

if let Some(liquidity_source) = self.liquidity_source.as_ref() {
let mut stop_liquidity_handler = self.stop_sender.subscribe();
let liquidity_handler = Arc::clone(&liquidity_source);
let liquidity_logger = Arc::clone(&self.logger);
background_tasks.spawn_on(
async move {
loop {
tokio::select! {
_ = stop_liquidity_handler.changed() => {
log_debug!(
liquidity_logger,
"Stopping processing liquidity events.",
);
return;
}
_ = liquidity_handler.handle_next_event() => {}
self.runtime.spawn_background_task(async move {
loop {
tokio::select! {
_ = stop_liquidity_handler.changed() => {
log_debug!(
liquidity_logger,
"Stopping processing liquidity events.",
);
return;
}
_ = liquidity_handler.handle_next_event() => {}
}
},
runtime_handle,
);
}
});
}

debug_assert!(self.background_tasks.lock().unwrap().is_none());
*self.background_tasks.lock().unwrap() = Some(background_tasks);

debug_assert!(self.cancellable_background_tasks.lock().unwrap().is_none());
*self.cancellable_background_tasks.lock().unwrap() = Some(cancellable_background_tasks);

log_info!(self.logger, "Startup complete.");
*is_running_lock = true;
Ok(())
Expand DownExpand Up@@ -649,15 +621,7 @@ impl Node {
}

// Cancel cancellable background tasks
if let Some(mut tasks) = self.cancellable_background_tasks.lock().unwrap().take() {
let runtime_handle = self.runtime.handle();
tasks.abort_all();
tokio::task::block_in_place(move || {
runtime_handle.block_on(async { while let Some(_) = tasks.join_next().await {} })
});
} else {
debug_assert!(false, "Expected some cancellable background tasks");
};
self.runtime.abort_cancellable_background_tasks();

// Disconnect all peers.
self.peer_manager.disconnect_all_peers();
Expand All@@ -668,91 +632,13 @@ impl Node {
log_debug!(self.logger, "Stopped chain sources.");

// Wait until non-cancellable background tasks (mod LDK's background processor) are done.
let runtime_handle = self.runtime.handle();
if let Some(mut tasks) = self.background_tasks.lock().unwrap().take() {
tokio::task::block_in_place(move || {
runtime_handle.block_on(async {
loop {
let timeout_fut = tokio::time::timeout(
Duration::from_secs(BACKGROUND_TASK_SHUTDOWN_TIMEOUT_SECS),
tasks.join_next_with_id(),
);
match timeout_fut.await {
Ok(Some(Ok((id, _)))) => {
log_trace!(self.logger, "Stopped background task with id {}", id);
},
Ok(Some(Err(e))) => {
tasks.abort_all();
log_trace!(self.logger, "Stopping background task failed: {}", e);
break;
},
Ok(None) => {
log_debug!(self.logger, "Stopped all background tasks");
break;
},
Err(e) => {
tasks.abort_all();
log_error!(
self.logger,
"Stopping background task timed out: {}",
e
);
break;
},
}
}
})
});
} else {
debug_assert!(false, "Expected some background tasks");
};
self.runtime.wait_on_background_tasks();

// Wait until background processing stopped, at least until a timeout is reached.
if let Some(background_processor_task) =
self.background_processor_task.lock().unwrap().take()
{
let abort_handle = background_processor_task.abort_handle();
let timeout_res = tokio::task::block_in_place(move || {
self.runtime.block_on(async {
tokio::time::timeout(
Duration::from_secs(LDK_EVENT_HANDLER_SHUTDOWN_TIMEOUT_SECS),
background_processor_task,
)
.await
})
});

match timeout_res {
Ok(stop_res) => match stop_res {
Ok(()) => log_debug!(self.logger, "Stopped background processing of events."),
Err(e) => {
abort_handle.abort();
log_error!(
self.logger,
"Stopping event handling failed. This should never happen: {}",
e
);
panic!("Stopping event handling failed. This should never happen.");
},
},
Err(e) => {
abort_handle.abort();
log_error!(self.logger, "Stopping event handling timed out: {}", e);
},
}
} else {
debug_assert!(false, "Expected a background processing task");
};
// Finally, wait until background processing stopped, at least until a timeout is reached.
self.runtime.wait_on_background_processor_task();

#[cfg(tokio_unstable)]
{
let runtime_handle = self.runtime.handle();
log_trace!(
self.logger,
"Active runtime tasks left prior to shutdown: {}",
runtime_handle.metrics().active_tasks_count()
);
}
self.runtime.log_metrics();

log_info!(self.logger, "Shutdown complete.");
*is_running_lock = false;
Expand Down
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 4 additions & 11 deletions src/builder.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -668,9 +668,9 @@ impl NodeBuilder {
let logger = setup_logger(&self.log_writer_config, &self.config)?;

let runtime = if let Some(handle) = self.runtime_handle.as_ref() {
Arc::new(Runtime::with_handle(handle.clone()))
Arc::new(Runtime::with_handle(handle.clone(), Arc::clone(&logger)))
} else {
Arc::new(Runtime::new().map_err(|e| {
Arc::new(Runtime::new(Arc::clone(&logger)).map_err(|e| {
log_error!(logger, "Failed to setup tokio runtime: {}", e);
BuildError::RuntimeSetupFailed
})?)
Expand DownExpand Up@@ -715,9 +715,9 @@ impl NodeBuilder {
let logger = setup_logger(&self.log_writer_config, &self.config)?;

let runtime = if let Some(handle) = self.runtime_handle.as_ref() {
Arc::new(Runtime::with_handle(handle.clone()))
Arc::new(Runtime::with_handle(handle.clone(), Arc::clone(&logger)))
} else {
Arc::new(Runtime::new().map_err(|e| {
Arc::new(Runtime::new(Arc::clone(&logger)).map_err(|e| {
log_error!(logger, "Failed to setup tokio runtime: {}", e);
BuildError::RuntimeSetupFailed
})?)
Expand DownExpand Up@@ -1668,18 +1668,11 @@ fn build_with_store_internal(
};

let (stop_sender, _) = tokio::sync::watch::channel(());
let background_processor_task = Mutex::new(None);
let background_tasks = Mutex::new(None);
let cancellable_background_tasks = Mutex::new(None);

let is_running = Arc::new(RwLock::new(false));

Ok(Node {
runtime,
stop_sender,
background_processor_task,
background_tasks,
cancellable_background_tasks,
config,
wallet,
chain_source,
Expand Down
4 changes: 2 additions & 2 deletions src/event.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -1059,7 +1059,7 @@ where
forwarding_channel_manager.process_pending_htlc_forwards();
};

self.runtime.spawn(future);
self.runtime.spawn_cancellable_background_task(future);
},
LdkEvent::SpendableOutputs { outputs, channel_id } => {
match self.output_sweeper.track_spendable_outputs(outputs, channel_id, true, None) {
Expand DownExpand Up@@ -1441,7 +1441,7 @@ where
}
}
};
self.runtime.spawn(future);
self.runtime.spawn_cancellable_background_task(future);
},
LdkEvent::BumpTransaction(bte) => {
match bte {
Expand Down
2 changes: 1 addition & 1 deletion src/gossip.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -144,6 +144,6 @@ impl RuntimeSpawner {

impl FutureSpawner for RuntimeSpawner {
fn spawn<T: Future<Output = ()> + Send + 'static>(&self, future: T) {
self.runtime.spawn(future);
self.runtime.spawn_cancellable_background_task(future);
}
}
186 changes: 36 additions & 150 deletions src/lib.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -128,9 +128,8 @@ pub use builder::NodeBuilder as Builder;

use chain::ChainSource;
use config::{
default_user_config, may_announce_channel, ChannelConfig, Config,
BACKGROUND_TASK_SHUTDOWN_TIMEOUT_SECS, LDK_EVENT_HANDLER_SHUTDOWN_TIMEOUT_SECS,
NODE_ANN_BCAST_INTERVAL, PEER_RECONNECTION_INTERVAL, RGS_SYNC_INTERVAL,
default_user_config, may_announce_channel, ChannelConfig, Config, NODE_ANN_BCAST_INTERVAL,
PEER_RECONNECTION_INTERVAL, RGS_SYNC_INTERVAL,
};
use connection::ConnectionManager;
use event::{EventHandler, EventQueue};
Expand DownExpand Up@@ -181,9 +180,6 @@ uniffi::include_scaffolding!("ldk_node");
pub struct Node {
runtime: Arc<Runtime>,
stop_sender: tokio::sync::watch::Sender<()>,
background_processor_task: Mutex<Option<tokio::task::JoinHandle<()>>>,
background_tasks: Mutex<Option<tokio::task::JoinSet<()>>>,
cancellable_background_tasks: Mutex<Option<tokio::task::JoinSet<()>>>,
config: Arc<Config>,
wallet: Arc<Wallet>,
chain_source: Arc<ChainSource>,
Expand DownExpand Up@@ -226,10 +222,6 @@ impl Node {
return Err(Error::AlreadyRunning);
}

let mut background_tasks = tokio::task::JoinSet::new();
let mut cancellable_background_tasks = tokio::task::JoinSet::new();
let runtime_handle = self.runtime.handle();

log_info!(
self.logger,
"Starting up LDK Node with node ID {} on network: {}",
Expand All@@ -253,27 +245,19 @@ impl Node {
let sync_cman = Arc::clone(&self.channel_manager);
let sync_cmon = Arc::clone(&self.chain_monitor);
let sync_sweeper = Arc::clone(&self.output_sweeper);
background_tasks.spawn_on(
async move {
chain_source
.continuously_sync_wallets(
stop_sync_receiver,
sync_cman,
sync_cmon,
sync_sweeper,
)
.await;
},
runtime_handle,
);
self.runtime.spawn_background_task(async move {
chain_source
.continuously_sync_wallets(stop_sync_receiver, sync_cman, sync_cmon, sync_sweeper)
.await;
});

if self.gossip_source.is_rgs() {
let gossip_source = Arc::clone(&self.gossip_source);
let gossip_sync_store = Arc::clone(&self.kv_store);
let gossip_sync_logger = Arc::clone(&self.logger);
let gossip_node_metrics = Arc::clone(&self.node_metrics);
let mut stop_gossip_sync = self.stop_sender.subscribe();
cancellable_background_tasks.spawn_on(async move {
self.runtime.spawn_cancellable_background_task(async move {
let mut interval = tokio::time::interval(RGS_SYNC_INTERVAL);
loop {
tokio::select! {
Expand DownExpand Up@@ -314,7 +298,7 @@ impl Node {
}
}
}
}, runtime_handle);
});
}

if let Some(listening_addresses) = &self.config.listening_addresses {
Expand All@@ -340,7 +324,7 @@ impl Node {
bind_addrs.extend(resolved_address);
}

cancellable_background_tasks.spawn_on(async move {
self.runtime.spawn_cancellable_background_task(async move {
{
let listener =
tokio::net::TcpListener::bind(&*bind_addrs).await
Expand DownExpand Up@@ -378,7 +362,7 @@ impl Node {
}

listening_indicator.store(false, Ordering::Release);
}, runtime_handle);
});
}

// Regularly reconnect to persisted peers.
Expand All@@ -387,7 +371,7 @@ impl Node {
let connect_logger = Arc::clone(&self.logger);
let connect_peer_store = Arc::clone(&self.peer_store);
let mut stop_connect = self.stop_sender.subscribe();
cancellable_background_tasks.spawn_on(async move {
self.runtime.spawn_cancellable_background_task(async move {
let mut interval = tokio::time::interval(PEER_RECONNECTION_INTERVAL);
interval.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Skip);
loop {
Expand DownExpand Up@@ -415,7 +399,7 @@ impl Node {
}
}
}
}, runtime_handle);
});

// Regularly broadcast node announcements.
let bcast_cm = Arc::clone(&self.channel_manager);
Expand All@@ -427,7 +411,7 @@ impl Node {
let mut stop_bcast = self.stop_sender.subscribe();
let node_alias = self.config.node_alias.clone();
if may_announce_channel(&self.config).is_ok() {
cancellable_background_tasks.spawn_on(async move {
self.runtime.spawn_cancellable_background_task(async move {
// We check every 30 secs whether our last broadcast is NODE_ANN_BCAST_INTERVAL away.
#[cfg(not(test))]
let mut interval = tokio::time::interval(Duration::from_secs(30));
Expand DownExpand Up@@ -498,15 +482,14 @@ impl Node {
}
}
}
}, runtime_handle);
});
}

let stop_tx_bcast = self.stop_sender.subscribe();
let chain_source = Arc::clone(&self.chain_source);
cancellable_background_tasks.spawn_on(
async move { chain_source.continuously_process_broadcast_queue(stop_tx_bcast).await },
runtime_handle,
);
self.runtime.spawn_cancellable_background_task(async move {
chain_source.continuously_process_broadcast_queue(stop_tx_bcast).await
});

let bump_tx_event_handler = Arc::new(BumpTransactionEventHandler::new(
Arc::clone(&self.tx_broadcaster),
Expand DownExpand Up@@ -563,7 +546,7 @@ impl Node {
})
};

let handle = self.runtime.spawn(async move {
self.runtime.spawn_background_processor_task(async move {
process_events_async(
background_persister,
|e| background_event_handler.handle_event(e),
Expand All@@ -584,38 +567,27 @@ impl Node {
panic!("Failed to process events");
});
});
debug_assert!(self.background_processor_task.lock().unwrap().is_none());
*self.background_processor_task.lock().unwrap() = Some(handle);

if let Some(liquidity_source) = self.liquidity_source.as_ref() {
let mut stop_liquidity_handler = self.stop_sender.subscribe();
let liquidity_handler = Arc::clone(&liquidity_source);
let liquidity_logger = Arc::clone(&self.logger);
background_tasks.spawn_on(
async move {
loop {
tokio::select! {
_ = stop_liquidity_handler.changed() => {
log_debug!(
liquidity_logger,
"Stopping processing liquidity events.",
);
return;
}
_ = liquidity_handler.handle_next_event() => {}
self.runtime.spawn_background_task(async move {
loop {
tokio::select! {
_ = stop_liquidity_handler.changed() => {
log_debug!(
liquidity_logger,
"Stopping processing liquidity events.",
);
return;
}
_ = liquidity_handler.handle_next_event() => {}
}
},
runtime_handle,
);
}
});
}

debug_assert!(self.background_tasks.lock().unwrap().is_none());
*self.background_tasks.lock().unwrap() = Some(background_tasks);

debug_assert!(self.cancellable_background_tasks.lock().unwrap().is_none());
*self.cancellable_background_tasks.lock().unwrap() = Some(cancellable_background_tasks);

log_info!(self.logger, "Startup complete.");
*is_running_lock = true;
Ok(())
Expand DownExpand Up@@ -649,15 +621,7 @@ impl Node {
}

// Cancel cancellable background tasks
if let Some(mut tasks) = self.cancellable_background_tasks.lock().unwrap().take() {
let runtime_handle = self.runtime.handle();
tasks.abort_all();
tokio::task::block_in_place(move || {
runtime_handle.block_on(async { while let Some(_) = tasks.join_next().await {} })
});
} else {
debug_assert!(false, "Expected some cancellable background tasks");
};
self.runtime.abort_cancellable_background_tasks();

// Disconnect all peers.
self.peer_manager.disconnect_all_peers();
Expand All@@ -668,91 +632,13 @@ impl Node {
log_debug!(self.logger, "Stopped chain sources.");

// Wait until non-cancellable background tasks (mod LDK's background processor) are done.
let runtime_handle = self.runtime.handle();
if let Some(mut tasks) = self.background_tasks.lock().unwrap().take() {
tokio::task::block_in_place(move || {
runtime_handle.block_on(async {
loop {
let timeout_fut = tokio::time::timeout(
Duration::from_secs(BACKGROUND_TASK_SHUTDOWN_TIMEOUT_SECS),
tasks.join_next_with_id(),
);
match timeout_fut.await {
Ok(Some(Ok((id, _)))) => {
log_trace!(self.logger, "Stopped background task with id {}", id);
},
Ok(Some(Err(e))) => {
tasks.abort_all();
log_trace!(self.logger, "Stopping background task failed: {}", e);
break;
},
Ok(None) => {
log_debug!(self.logger, "Stopped all background tasks");
break;
},
Err(e) => {
tasks.abort_all();
log_error!(
self.logger,
"Stopping background task timed out: {}",
e
);
break;
},
}
}
})
});
} else {
debug_assert!(false, "Expected some background tasks");
};
self.runtime.wait_on_background_tasks();

// Wait until background processing stopped, at least until a timeout is reached.
if let Some(background_processor_task) =
self.background_processor_task.lock().unwrap().take()
{
let abort_handle = background_processor_task.abort_handle();
let timeout_res = tokio::task::block_in_place(move || {
self.runtime.block_on(async {
tokio::time::timeout(
Duration::from_secs(LDK_EVENT_HANDLER_SHUTDOWN_TIMEOUT_SECS),
background_processor_task,
)
.await
})
});

match timeout_res {
Ok(stop_res) => match stop_res {
Ok(()) => log_debug!(self.logger, "Stopped background processing of events."),
Err(e) => {
abort_handle.abort();
log_error!(
self.logger,
"Stopping event handling failed. This should never happen: {}",
e
);
panic!("Stopping event handling failed. This should never happen.");
},
},
Err(e) => {
abort_handle.abort();
log_error!(self.logger, "Stopping event handling timed out: {}", e);
},
}
} else {
debug_assert!(false, "Expected a background processing task");
};
// Finally, wait until background processing stopped, at least until a timeout is reached.
self.runtime.wait_on_background_processor_task();

#[cfg(tokio_unstable)]
{
let runtime_handle = self.runtime.handle();
log_trace!(
self.logger,
"Active runtime tasks left prior to shutdown: {}",
runtime_handle.metrics().active_tasks_count()
);
}
self.runtime.log_metrics();

log_info!(self.logger, "Shutdown complete.");
*is_running_lock = false;
Expand Down
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 4 additions & 11 deletions src/builder.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -668,9 +668,9 @@ impl NodeBuilder {
let logger = setup_logger(&self.log_writer_config, &self.config)?;

let runtime = if let Some(handle) = self.runtime_handle.as_ref() {
Arc::new(Runtime::with_handle(handle.clone()))
Arc::new(Runtime::with_handle(handle.clone(), Arc::clone(&logger)))
} else {
Arc::new(Runtime::new().map_err(|e| {
Arc::new(Runtime::new(Arc::clone(&logger)).map_err(|e| {
log_error!(logger, "Failed to setup tokio runtime: {}", e);
BuildError::RuntimeSetupFailed
})?)
Expand DownExpand Up@@ -715,9 +715,9 @@ impl NodeBuilder {
let logger = setup_logger(&self.log_writer_config, &self.config)?;

let runtime = if let Some(handle) = self.runtime_handle.as_ref() {
Arc::new(Runtime::with_handle(handle.clone()))
Arc::new(Runtime::with_handle(handle.clone(), Arc::clone(&logger)))
} else {
Arc::new(Runtime::new().map_err(|e| {
Arc::new(Runtime::new(Arc::clone(&logger)).map_err(|e| {
log_error!(logger, "Failed to setup tokio runtime: {}", e);
BuildError::RuntimeSetupFailed
})?)
Expand DownExpand Up@@ -1668,18 +1668,11 @@ fn build_with_store_internal(
};

let (stop_sender, _) = tokio::sync::watch::channel(());
let background_processor_task = Mutex::new(None);
let background_tasks = Mutex::new(None);
let cancellable_background_tasks = Mutex::new(None);

let is_running = Arc::new(RwLock::new(false));

Ok(Node {
runtime,
stop_sender,
background_processor_task,
background_tasks,
cancellable_background_tasks,
config,
wallet,
chain_source,
Expand Down
4 changes: 2 additions & 2 deletions src/event.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -1059,7 +1059,7 @@ where
forwarding_channel_manager.process_pending_htlc_forwards();
};

self.runtime.spawn(future);
self.runtime.spawn_cancellable_background_task(future);
},
LdkEvent::SpendableOutputs { outputs, channel_id } => {
match self.output_sweeper.track_spendable_outputs(outputs, channel_id, true, None) {
Expand DownExpand Up@@ -1441,7 +1441,7 @@ where
}
}
};
self.runtime.spawn(future);
self.runtime.spawn_cancellable_background_task(future);
},
LdkEvent::BumpTransaction(bte) => {
match bte {
Expand Down
2 changes: 1 addition & 1 deletion src/gossip.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -144,6 +144,6 @@ impl RuntimeSpawner {

impl FutureSpawner for RuntimeSpawner {
fn spawn<T: Future<Output = ()> + Send + 'static>(&self, future: T) {
self.runtime.spawn(future);
self.runtime.spawn_cancellable_background_task(future);
}
}
186 changes: 36 additions & 150 deletions src/lib.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -128,9 +128,8 @@ pub use builder::NodeBuilder as Builder;

use chain::ChainSource;
use config::{
default_user_config, may_announce_channel, ChannelConfig, Config,
BACKGROUND_TASK_SHUTDOWN_TIMEOUT_SECS, LDK_EVENT_HANDLER_SHUTDOWN_TIMEOUT_SECS,
NODE_ANN_BCAST_INTERVAL, PEER_RECONNECTION_INTERVAL, RGS_SYNC_INTERVAL,
default_user_config, may_announce_channel, ChannelConfig, Config, NODE_ANN_BCAST_INTERVAL,
PEER_RECONNECTION_INTERVAL, RGS_SYNC_INTERVAL,
};
use connection::ConnectionManager;
use event::{EventHandler, EventQueue};
Expand DownExpand Up@@ -181,9 +180,6 @@ uniffi::include_scaffolding!("ldk_node");
pub struct Node {
runtime: Arc<Runtime>,
stop_sender: tokio::sync::watch::Sender<()>,
background_processor_task: Mutex<Option<tokio::task::JoinHandle<()>>>,
background_tasks: Mutex<Option<tokio::task::JoinSet<()>>>,
cancellable_background_tasks: Mutex<Option<tokio::task::JoinSet<()>>>,
config: Arc<Config>,
wallet: Arc<Wallet>,
chain_source: Arc<ChainSource>,
Expand DownExpand Up@@ -226,10 +222,6 @@ impl Node {
return Err(Error::AlreadyRunning);
}

let mut background_tasks = tokio::task::JoinSet::new();
let mut cancellable_background_tasks = tokio::task::JoinSet::new();
let runtime_handle = self.runtime.handle();

log_info!(
self.logger,
"Starting up LDK Node with node ID {} on network: {}",
Expand All@@ -253,27 +245,19 @@ impl Node {
let sync_cman = Arc::clone(&self.channel_manager);
let sync_cmon = Arc::clone(&self.chain_monitor);
let sync_sweeper = Arc::clone(&self.output_sweeper);
background_tasks.spawn_on(
async move {
chain_source
.continuously_sync_wallets(
stop_sync_receiver,
sync_cman,
sync_cmon,
sync_sweeper,
)
.await;
},
runtime_handle,
);
self.runtime.spawn_background_task(async move {
chain_source
.continuously_sync_wallets(stop_sync_receiver, sync_cman, sync_cmon, sync_sweeper)
.await;
});

if self.gossip_source.is_rgs() {
let gossip_source = Arc::clone(&self.gossip_source);
let gossip_sync_store = Arc::clone(&self.kv_store);
let gossip_sync_logger = Arc::clone(&self.logger);
let gossip_node_metrics = Arc::clone(&self.node_metrics);
let mut stop_gossip_sync = self.stop_sender.subscribe();
cancellable_background_tasks.spawn_on(async move {
self.runtime.spawn_cancellable_background_task(async move {
let mut interval = tokio::time::interval(RGS_SYNC_INTERVAL);
loop {
tokio::select! {
Expand DownExpand Up@@ -314,7 +298,7 @@ impl Node {
}
}
}
}, runtime_handle);
});
}

if let Some(listening_addresses) = &self.config.listening_addresses {
Expand All@@ -340,7 +324,7 @@ impl Node {
bind_addrs.extend(resolved_address);
}

cancellable_background_tasks.spawn_on(async move {
self.runtime.spawn_cancellable_background_task(async move {
{
let listener =
tokio::net::TcpListener::bind(&*bind_addrs).await
Expand DownExpand Up@@ -378,7 +362,7 @@ impl Node {
}

listening_indicator.store(false, Ordering::Release);
}, runtime_handle);
});
}

// Regularly reconnect to persisted peers.
Expand All@@ -387,7 +371,7 @@ impl Node {
let connect_logger = Arc::clone(&self.logger);
let connect_peer_store = Arc::clone(&self.peer_store);
let mut stop_connect = self.stop_sender.subscribe();
cancellable_background_tasks.spawn_on(async move {
self.runtime.spawn_cancellable_background_task(async move {
let mut interval = tokio::time::interval(PEER_RECONNECTION_INTERVAL);
interval.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Skip);
loop {
Expand DownExpand Up@@ -415,7 +399,7 @@ impl Node {
}
}
}
}, runtime_handle);
});

// Regularly broadcast node announcements.
let bcast_cm = Arc::clone(&self.channel_manager);
Expand All@@ -427,7 +411,7 @@ impl Node {
let mut stop_bcast = self.stop_sender.subscribe();
let node_alias = self.config.node_alias.clone();
if may_announce_channel(&self.config).is_ok() {
cancellable_background_tasks.spawn_on(async move {
self.runtime.spawn_cancellable_background_task(async move {
// We check every 30 secs whether our last broadcast is NODE_ANN_BCAST_INTERVAL away.
#[cfg(not(test))]
let mut interval = tokio::time::interval(Duration::from_secs(30));
Expand DownExpand Up@@ -498,15 +482,14 @@ impl Node {
}
}
}
}, runtime_handle);
});
}

let stop_tx_bcast = self.stop_sender.subscribe();
let chain_source = Arc::clone(&self.chain_source);
cancellable_background_tasks.spawn_on(
async move { chain_source.continuously_process_broadcast_queue(stop_tx_bcast).await },
runtime_handle,
);
self.runtime.spawn_cancellable_background_task(async move {
chain_source.continuously_process_broadcast_queue(stop_tx_bcast).await
});

let bump_tx_event_handler = Arc::new(BumpTransactionEventHandler::new(
Arc::clone(&self.tx_broadcaster),
Expand DownExpand Up@@ -563,7 +546,7 @@ impl Node {
})
};

let handle = self.runtime.spawn(async move {
self.runtime.spawn_background_processor_task(async move {
process_events_async(
background_persister,
|e| background_event_handler.handle_event(e),
Expand All@@ -584,38 +567,27 @@ impl Node {
panic!("Failed to process events");
});
});
debug_assert!(self.background_processor_task.lock().unwrap().is_none());
*self.background_processor_task.lock().unwrap() = Some(handle);

if let Some(liquidity_source) = self.liquidity_source.as_ref() {
let mut stop_liquidity_handler = self.stop_sender.subscribe();
let liquidity_handler = Arc::clone(&liquidity_source);
let liquidity_logger = Arc::clone(&self.logger);
background_tasks.spawn_on(
async move {
loop {
tokio::select! {
_ = stop_liquidity_handler.changed() => {
log_debug!(
liquidity_logger,
"Stopping processing liquidity events.",
);
return;
}
_ = liquidity_handler.handle_next_event() => {}
self.runtime.spawn_background_task(async move {
loop {
tokio::select! {
_ = stop_liquidity_handler.changed() => {
log_debug!(
liquidity_logger,
"Stopping processing liquidity events.",
);
return;
}
_ = liquidity_handler.handle_next_event() => {}
}
},
runtime_handle,
);
}
});
}

debug_assert!(self.background_tasks.lock().unwrap().is_none());
*self.background_tasks.lock().unwrap() = Some(background_tasks);

debug_assert!(self.cancellable_background_tasks.lock().unwrap().is_none());
*self.cancellable_background_tasks.lock().unwrap() = Some(cancellable_background_tasks);

log_info!(self.logger, "Startup complete.");
*is_running_lock = true;
Ok(())
Expand DownExpand Up@@ -649,15 +621,7 @@ impl Node {
}

// Cancel cancellable background tasks
if let Some(mut tasks) = self.cancellable_background_tasks.lock().unwrap().take() {
let runtime_handle = self.runtime.handle();
tasks.abort_all();
tokio::task::block_in_place(move || {
runtime_handle.block_on(async { while let Some(_) = tasks.join_next().await {} })
});
} else {
debug_assert!(false, "Expected some cancellable background tasks");
};
self.runtime.abort_cancellable_background_tasks();

// Disconnect all peers.
self.peer_manager.disconnect_all_peers();
Expand All@@ -668,91 +632,13 @@ impl Node {
log_debug!(self.logger, "Stopped chain sources.");

// Wait until non-cancellable background tasks (mod LDK's background processor) are done.
let runtime_handle = self.runtime.handle();
if let Some(mut tasks) = self.background_tasks.lock().unwrap().take() {
tokio::task::block_in_place(move || {
runtime_handle.block_on(async {
loop {
let timeout_fut = tokio::time::timeout(
Duration::from_secs(BACKGROUND_TASK_SHUTDOWN_TIMEOUT_SECS),
tasks.join_next_with_id(),
);
match timeout_fut.await {
Ok(Some(Ok((id, _)))) => {
log_trace!(self.logger, "Stopped background task with id {}", id);
},
Ok(Some(Err(e))) => {
tasks.abort_all();
log_trace!(self.logger, "Stopping background task failed: {}", e);
break;
},
Ok(None) => {
log_debug!(self.logger, "Stopped all background tasks");
break;
},
Err(e) => {
tasks.abort_all();
log_error!(
self.logger,
"Stopping background task timed out: {}",
e
);
break;
},
}
}
})
});
} else {
debug_assert!(false, "Expected some background tasks");
};
self.runtime.wait_on_background_tasks();

// Wait until background processing stopped, at least until a timeout is reached.
if let Some(background_processor_task) =
self.background_processor_task.lock().unwrap().take()
{
let abort_handle = background_processor_task.abort_handle();
let timeout_res = tokio::task::block_in_place(move || {
self.runtime.block_on(async {
tokio::time::timeout(
Duration::from_secs(LDK_EVENT_HANDLER_SHUTDOWN_TIMEOUT_SECS),
background_processor_task,
)
.await
})
});

match timeout_res {
Ok(stop_res) => match stop_res {
Ok(()) => log_debug!(self.logger, "Stopped background processing of events."),
Err(e) => {
abort_handle.abort();
log_error!(
self.logger,
"Stopping event handling failed. This should never happen: {}",
e
);
panic!("Stopping event handling failed. This should never happen.");
},
},
Err(e) => {
abort_handle.abort();
log_error!(self.logger, "Stopping event handling timed out: {}", e);
},
}
} else {
debug_assert!(false, "Expected a background processing task");
};
// Finally, wait until background processing stopped, at least until a timeout is reached.
self.runtime.wait_on_background_processor_task();

#[cfg(tokio_unstable)]
{
let runtime_handle = self.runtime.handle();
log_trace!(
self.logger,
"Active runtime tasks left prior to shutdown: {}",
runtime_handle.metrics().active_tasks_count()
);
}
self.runtime.log_metrics();

log_info!(self.logger, "Shutdown complete.");
*is_running_lock = false;
Expand Down
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 4 additions & 11 deletions src/builder.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -668,9 +668,9 @@ impl NodeBuilder {
let logger = setup_logger(&self.log_writer_config, &self.config)?;

let runtime = if let Some(handle) = self.runtime_handle.as_ref() {
Arc::new(Runtime::with_handle(handle.clone()))
Arc::new(Runtime::with_handle(handle.clone(), Arc::clone(&logger)))
} else {
Arc::new(Runtime::new().map_err(|e| {
Arc::new(Runtime::new(Arc::clone(&logger)).map_err(|e| {
log_error!(logger, "Failed to setup tokio runtime: {}", e);
BuildError::RuntimeSetupFailed
})?)
Expand DownExpand Up@@ -715,9 +715,9 @@ impl NodeBuilder {
let logger = setup_logger(&self.log_writer_config, &self.config)?;

let runtime = if let Some(handle) = self.runtime_handle.as_ref() {
Arc::new(Runtime::with_handle(handle.clone()))
Arc::new(Runtime::with_handle(handle.clone(), Arc::clone(&logger)))
} else {
Arc::new(Runtime::new().map_err(|e| {
Arc::new(Runtime::new(Arc::clone(&logger)).map_err(|e| {
log_error!(logger, "Failed to setup tokio runtime: {}", e);
BuildError::RuntimeSetupFailed
})?)
Expand DownExpand Up@@ -1668,18 +1668,11 @@ fn build_with_store_internal(
};

let (stop_sender, _) = tokio::sync::watch::channel(());
let background_processor_task = Mutex::new(None);
let background_tasks = Mutex::new(None);
let cancellable_background_tasks = Mutex::new(None);

let is_running = Arc::new(RwLock::new(false));

Ok(Node {
runtime,
stop_sender,
background_processor_task,
background_tasks,
cancellable_background_tasks,
config,
wallet,
chain_source,
Expand Down
4 changes: 2 additions & 2 deletions src/event.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -1059,7 +1059,7 @@ where
forwarding_channel_manager.process_pending_htlc_forwards();
};

self.runtime.spawn(future);
self.runtime.spawn_cancellable_background_task(future);
},
LdkEvent::SpendableOutputs { outputs, channel_id } => {
match self.output_sweeper.track_spendable_outputs(outputs, channel_id, true, None) {
Expand DownExpand Up@@ -1441,7 +1441,7 @@ where
}
}
};
self.runtime.spawn(future);
self.runtime.spawn_cancellable_background_task(future);
},
LdkEvent::BumpTransaction(bte) => {
match bte {
Expand Down
2 changes: 1 addition & 1 deletion src/gossip.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -144,6 +144,6 @@ impl RuntimeSpawner {

impl FutureSpawner for RuntimeSpawner {
fn spawn<T: Future<Output = ()> + Send + 'static>(&self, future: T) {
self.runtime.spawn(future);
self.runtime.spawn_cancellable_background_task(future);
}
}
186 changes: 36 additions & 150 deletions src/lib.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -128,9 +128,8 @@ pub use builder::NodeBuilder as Builder;

use chain::ChainSource;
use config::{
default_user_config, may_announce_channel, ChannelConfig, Config,
BACKGROUND_TASK_SHUTDOWN_TIMEOUT_SECS, LDK_EVENT_HANDLER_SHUTDOWN_TIMEOUT_SECS,
NODE_ANN_BCAST_INTERVAL, PEER_RECONNECTION_INTERVAL, RGS_SYNC_INTERVAL,
default_user_config, may_announce_channel, ChannelConfig, Config, NODE_ANN_BCAST_INTERVAL,
PEER_RECONNECTION_INTERVAL, RGS_SYNC_INTERVAL,
};
use connection::ConnectionManager;
use event::{EventHandler, EventQueue};
Expand DownExpand Up@@ -181,9 +180,6 @@ uniffi::include_scaffolding!("ldk_node");
pub struct Node {
runtime: Arc<Runtime>,
stop_sender: tokio::sync::watch::Sender<()>,
background_processor_task: Mutex<Option<tokio::task::JoinHandle<()>>>,
background_tasks: Mutex<Option<tokio::task::JoinSet<()>>>,
cancellable_background_tasks: Mutex<Option<tokio::task::JoinSet<()>>>,
config: Arc<Config>,
wallet: Arc<Wallet>,
chain_source: Arc<ChainSource>,
Expand DownExpand Up@@ -226,10 +222,6 @@ impl Node {
return Err(Error::AlreadyRunning);
}

let mut background_tasks = tokio::task::JoinSet::new();
let mut cancellable_background_tasks = tokio::task::JoinSet::new();
let runtime_handle = self.runtime.handle();

log_info!(
self.logger,
"Starting up LDK Node with node ID {} on network: {}",
Expand All@@ -253,27 +245,19 @@ impl Node {
let sync_cman = Arc::clone(&self.channel_manager);
let sync_cmon = Arc::clone(&self.chain_monitor);
let sync_sweeper = Arc::clone(&self.output_sweeper);
background_tasks.spawn_on(
async move {
chain_source
.continuously_sync_wallets(
stop_sync_receiver,
sync_cman,
sync_cmon,
sync_sweeper,
)
.await;
},
runtime_handle,
);
self.runtime.spawn_background_task(async move {
chain_source
.continuously_sync_wallets(stop_sync_receiver, sync_cman, sync_cmon, sync_sweeper)
.await;
});

if self.gossip_source.is_rgs() {
let gossip_source = Arc::clone(&self.gossip_source);
let gossip_sync_store = Arc::clone(&self.kv_store);
let gossip_sync_logger = Arc::clone(&self.logger);
let gossip_node_metrics = Arc::clone(&self.node_metrics);
let mut stop_gossip_sync = self.stop_sender.subscribe();
cancellable_background_tasks.spawn_on(async move {
self.runtime.spawn_cancellable_background_task(async move {
let mut interval = tokio::time::interval(RGS_SYNC_INTERVAL);
loop {
tokio::select! {
Expand DownExpand Up@@ -314,7 +298,7 @@ impl Node {
}
}
}
}, runtime_handle);
});
}

if let Some(listening_addresses) = &self.config.listening_addresses {
Expand All@@ -340,7 +324,7 @@ impl Node {
bind_addrs.extend(resolved_address);
}

cancellable_background_tasks.spawn_on(async move {
self.runtime.spawn_cancellable_background_task(async move {
{
let listener =
tokio::net::TcpListener::bind(&*bind_addrs).await
Expand DownExpand Up@@ -378,7 +362,7 @@ impl Node {
}

listening_indicator.store(false, Ordering::Release);
}, runtime_handle);
});
}

// Regularly reconnect to persisted peers.
Expand All@@ -387,7 +371,7 @@ impl Node {
let connect_logger = Arc::clone(&self.logger);
let connect_peer_store = Arc::clone(&self.peer_store);
let mut stop_connect = self.stop_sender.subscribe();
cancellable_background_tasks.spawn_on(async move {
self.runtime.spawn_cancellable_background_task(async move {
let mut interval = tokio::time::interval(PEER_RECONNECTION_INTERVAL);
interval.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Skip);
loop {
Expand DownExpand Up@@ -415,7 +399,7 @@ impl Node {
}
}
}
}, runtime_handle);
});

// Regularly broadcast node announcements.
let bcast_cm = Arc::clone(&self.channel_manager);
Expand All@@ -427,7 +411,7 @@ impl Node {
let mut stop_bcast = self.stop_sender.subscribe();
let node_alias = self.config.node_alias.clone();
if may_announce_channel(&self.config).is_ok() {
cancellable_background_tasks.spawn_on(async move {
self.runtime.spawn_cancellable_background_task(async move {
// We check every 30 secs whether our last broadcast is NODE_ANN_BCAST_INTERVAL away.
#[cfg(not(test))]
let mut interval = tokio::time::interval(Duration::from_secs(30));
Expand DownExpand Up@@ -498,15 +482,14 @@ impl Node {
}
}
}
}, runtime_handle);
});
}

let stop_tx_bcast = self.stop_sender.subscribe();
let chain_source = Arc::clone(&self.chain_source);
cancellable_background_tasks.spawn_on(
async move { chain_source.continuously_process_broadcast_queue(stop_tx_bcast).await },
runtime_handle,
);
self.runtime.spawn_cancellable_background_task(async move {
chain_source.continuously_process_broadcast_queue(stop_tx_bcast).await
});

let bump_tx_event_handler = Arc::new(BumpTransactionEventHandler::new(
Arc::clone(&self.tx_broadcaster),
Expand DownExpand Up@@ -563,7 +546,7 @@ impl Node {
})
};

let handle = self.runtime.spawn(async move {
self.runtime.spawn_background_processor_task(async move {
process_events_async(
background_persister,
|e| background_event_handler.handle_event(e),
Expand All@@ -584,38 +567,27 @@ impl Node {
panic!("Failed to process events");
});
});
debug_assert!(self.background_processor_task.lock().unwrap().is_none());
*self.background_processor_task.lock().unwrap() = Some(handle);

if let Some(liquidity_source) = self.liquidity_source.as_ref() {
let mut stop_liquidity_handler = self.stop_sender.subscribe();
let liquidity_handler = Arc::clone(&liquidity_source);
let liquidity_logger = Arc::clone(&self.logger);
background_tasks.spawn_on(
async move {
loop {
tokio::select! {
_ = stop_liquidity_handler.changed() => {
log_debug!(
liquidity_logger,
"Stopping processing liquidity events.",
);
return;
}
_ = liquidity_handler.handle_next_event() => {}
self.runtime.spawn_background_task(async move {
loop {
tokio::select! {
_ = stop_liquidity_handler.changed() => {
log_debug!(
liquidity_logger,
"Stopping processing liquidity events.",
);
return;
}
_ = liquidity_handler.handle_next_event() => {}
}
},
runtime_handle,
);
}
});
}

debug_assert!(self.background_tasks.lock().unwrap().is_none());
*self.background_tasks.lock().unwrap() = Some(background_tasks);

debug_assert!(self.cancellable_background_tasks.lock().unwrap().is_none());
*self.cancellable_background_tasks.lock().unwrap() = Some(cancellable_background_tasks);

log_info!(self.logger, "Startup complete.");
*is_running_lock = true;
Ok(())
Expand DownExpand Up@@ -649,15 +621,7 @@ impl Node {
}

// Cancel cancellable background tasks
if let Some(mut tasks) = self.cancellable_background_tasks.lock().unwrap().take() {
let runtime_handle = self.runtime.handle();
tasks.abort_all();
tokio::task::block_in_place(move || {
runtime_handle.block_on(async { while let Some(_) = tasks.join_next().await {} })
});
} else {
debug_assert!(false, "Expected some cancellable background tasks");
};
self.runtime.abort_cancellable_background_tasks();

// Disconnect all peers.
self.peer_manager.disconnect_all_peers();
Expand All@@ -668,91 +632,13 @@ impl Node {
log_debug!(self.logger, "Stopped chain sources.");

// Wait until non-cancellable background tasks (mod LDK's background processor) are done.
let runtime_handle = self.runtime.handle();
if let Some(mut tasks) = self.background_tasks.lock().unwrap().take() {
tokio::task::block_in_place(move || {
runtime_handle.block_on(async {
loop {
let timeout_fut = tokio::time::timeout(
Duration::from_secs(BACKGROUND_TASK_SHUTDOWN_TIMEOUT_SECS),
tasks.join_next_with_id(),
);
match timeout_fut.await {
Ok(Some(Ok((id, _)))) => {
log_trace!(self.logger, "Stopped background task with id {}", id);
},
Ok(Some(Err(e))) => {
tasks.abort_all();
log_trace!(self.logger, "Stopping background task failed: {}", e);
break;
},
Ok(None) => {
log_debug!(self.logger, "Stopped all background tasks");
break;
},
Err(e) => {
tasks.abort_all();
log_error!(
self.logger,
"Stopping background task timed out: {}",
e
);
break;
},
}
}
})
});
} else {
debug_assert!(false, "Expected some background tasks");
};
self.runtime.wait_on_background_tasks();

// Wait until background processing stopped, at least until a timeout is reached.
if let Some(background_processor_task) =
self.background_processor_task.lock().unwrap().take()
{
let abort_handle = background_processor_task.abort_handle();
let timeout_res = tokio::task::block_in_place(move || {
self.runtime.block_on(async {
tokio::time::timeout(
Duration::from_secs(LDK_EVENT_HANDLER_SHUTDOWN_TIMEOUT_SECS),
background_processor_task,
)
.await
})
});

match timeout_res {
Ok(stop_res) => match stop_res {
Ok(()) => log_debug!(self.logger, "Stopped background processing of events."),
Err(e) => {
abort_handle.abort();
log_error!(
self.logger,
"Stopping event handling failed. This should never happen: {}",
e
);
panic!("Stopping event handling failed. This should never happen.");
},
},
Err(e) => {
abort_handle.abort();
log_error!(self.logger, "Stopping event handling timed out: {}", e);
},
}
} else {
debug_assert!(false, "Expected a background processing task");
};
// Finally, wait until background processing stopped, at least until a timeout is reached.
self.runtime.wait_on_background_processor_task();

#[cfg(tokio_unstable)]
{
let runtime_handle = self.runtime.handle();
log_trace!(
self.logger,
"Active runtime tasks left prior to shutdown: {}",
runtime_handle.metrics().active_tasks_count()
);
}
self.runtime.log_metrics();

log_info!(self.logger, "Shutdown complete.");
*is_running_lock = false;
Expand Down
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 4 additions & 11 deletions src/builder.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -668,9 +668,9 @@ impl NodeBuilder {
let logger = setup_logger(&self.log_writer_config, &self.config)?;

let runtime = if let Some(handle) = self.runtime_handle.as_ref() {
Arc::new(Runtime::with_handle(handle.clone()))
Arc::new(Runtime::with_handle(handle.clone(), Arc::clone(&logger)))
} else {
Arc::new(Runtime::new().map_err(|e| {
Arc::new(Runtime::new(Arc::clone(&logger)).map_err(|e| {
log_error!(logger, "Failed to setup tokio runtime: {}", e);
BuildError::RuntimeSetupFailed
})?)
Expand DownExpand Up@@ -715,9 +715,9 @@ impl NodeBuilder {
let logger = setup_logger(&self.log_writer_config, &self.config)?;

let runtime = if let Some(handle) = self.runtime_handle.as_ref() {
Arc::new(Runtime::with_handle(handle.clone()))
Arc::new(Runtime::with_handle(handle.clone(), Arc::clone(&logger)))
} else {
Arc::new(Runtime::new().map_err(|e| {
Arc::new(Runtime::new(Arc::clone(&logger)).map_err(|e| {
log_error!(logger, "Failed to setup tokio runtime: {}", e);
BuildError::RuntimeSetupFailed
})?)
Expand DownExpand Up@@ -1668,18 +1668,11 @@ fn build_with_store_internal(
};

let (stop_sender, _) = tokio::sync::watch::channel(());
let background_processor_task = Mutex::new(None);
let background_tasks = Mutex::new(None);
let cancellable_background_tasks = Mutex::new(None);

let is_running = Arc::new(RwLock::new(false));

Ok(Node {
runtime,
stop_sender,
background_processor_task,
background_tasks,
cancellable_background_tasks,
config,
wallet,
chain_source,
Expand Down
4 changes: 2 additions & 2 deletions src/event.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -1059,7 +1059,7 @@ where
forwarding_channel_manager.process_pending_htlc_forwards();
};

self.runtime.spawn(future);
self.runtime.spawn_cancellable_background_task(future);
},
LdkEvent::SpendableOutputs { outputs, channel_id } => {
match self.output_sweeper.track_spendable_outputs(outputs, channel_id, true, None) {
Expand DownExpand Up@@ -1441,7 +1441,7 @@ where
}
}
};
self.runtime.spawn(future);
self.runtime.spawn_cancellable_background_task(future);
},
LdkEvent::BumpTransaction(bte) => {
match bte {
Expand Down
2 changes: 1 addition & 1 deletion src/gossip.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -144,6 +144,6 @@ impl RuntimeSpawner {

impl FutureSpawner for RuntimeSpawner {
fn spawn<T: Future<Output = ()> + Send + 'static>(&self, future: T) {
self.runtime.spawn(future);
self.runtime.spawn_cancellable_background_task(future);
}
}
186 changes: 36 additions & 150 deletions src/lib.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -128,9 +128,8 @@ pub use builder::NodeBuilder as Builder;

use chain::ChainSource;
use config::{
default_user_config, may_announce_channel, ChannelConfig, Config,
BACKGROUND_TASK_SHUTDOWN_TIMEOUT_SECS, LDK_EVENT_HANDLER_SHUTDOWN_TIMEOUT_SECS,
NODE_ANN_BCAST_INTERVAL, PEER_RECONNECTION_INTERVAL, RGS_SYNC_INTERVAL,
default_user_config, may_announce_channel, ChannelConfig, Config, NODE_ANN_BCAST_INTERVAL,
PEER_RECONNECTION_INTERVAL, RGS_SYNC_INTERVAL,
};
use connection::ConnectionManager;
use event::{EventHandler, EventQueue};
Expand DownExpand Up@@ -181,9 +180,6 @@ uniffi::include_scaffolding!("ldk_node");
pub struct Node {
runtime: Arc<Runtime>,
stop_sender: tokio::sync::watch::Sender<()>,
background_processor_task: Mutex<Option<tokio::task::JoinHandle<()>>>,
background_tasks: Mutex<Option<tokio::task::JoinSet<()>>>,
cancellable_background_tasks: Mutex<Option<tokio::task::JoinSet<()>>>,
config: Arc<Config>,
wallet: Arc<Wallet>,
chain_source: Arc<ChainSource>,
Expand DownExpand Up@@ -226,10 +222,6 @@ impl Node {
return Err(Error::AlreadyRunning);
}

let mut background_tasks = tokio::task::JoinSet::new();
let mut cancellable_background_tasks = tokio::task::JoinSet::new();
let runtime_handle = self.runtime.handle();

log_info!(
self.logger,
"Starting up LDK Node with node ID {} on network: {}",
Expand All@@ -253,27 +245,19 @@ impl Node {
let sync_cman = Arc::clone(&self.channel_manager);
let sync_cmon = Arc::clone(&self.chain_monitor);
let sync_sweeper = Arc::clone(&self.output_sweeper);
background_tasks.spawn_on(
async move {
chain_source
.continuously_sync_wallets(
stop_sync_receiver,
sync_cman,
sync_cmon,
sync_sweeper,
)
.await;
},
runtime_handle,
);
self.runtime.spawn_background_task(async move {
chain_source
.continuously_sync_wallets(stop_sync_receiver, sync_cman, sync_cmon, sync_sweeper)
.await;
});

if self.gossip_source.is_rgs() {
let gossip_source = Arc::clone(&self.gossip_source);
let gossip_sync_store = Arc::clone(&self.kv_store);
let gossip_sync_logger = Arc::clone(&self.logger);
let gossip_node_metrics = Arc::clone(&self.node_metrics);
let mut stop_gossip_sync = self.stop_sender.subscribe();
cancellable_background_tasks.spawn_on(async move {
self.runtime.spawn_cancellable_background_task(async move {
let mut interval = tokio::time::interval(RGS_SYNC_INTERVAL);
loop {
tokio::select! {
Expand DownExpand Up@@ -314,7 +298,7 @@ impl Node {
}
}
}
}, runtime_handle);
});
}

if let Some(listening_addresses) = &self.config.listening_addresses {
Expand All@@ -340,7 +324,7 @@ impl Node {
bind_addrs.extend(resolved_address);
}

cancellable_background_tasks.spawn_on(async move {
self.runtime.spawn_cancellable_background_task(async move {
{
let listener =
tokio::net::TcpListener::bind(&*bind_addrs).await
Expand DownExpand Up@@ -378,7 +362,7 @@ impl Node {
}

listening_indicator.store(false, Ordering::Release);
}, runtime_handle);
});
}

// Regularly reconnect to persisted peers.
Expand All@@ -387,7 +371,7 @@ impl Node {
let connect_logger = Arc::clone(&self.logger);
let connect_peer_store = Arc::clone(&self.peer_store);
let mut stop_connect = self.stop_sender.subscribe();
cancellable_background_tasks.spawn_on(async move {
self.runtime.spawn_cancellable_background_task(async move {
let mut interval = tokio::time::interval(PEER_RECONNECTION_INTERVAL);
interval.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Skip);
loop {
Expand DownExpand Up@@ -415,7 +399,7 @@ impl Node {
}
}
}
}, runtime_handle);
});

// Regularly broadcast node announcements.
let bcast_cm = Arc::clone(&self.channel_manager);
Expand All@@ -427,7 +411,7 @@ impl Node {
let mut stop_bcast = self.stop_sender.subscribe();
let node_alias = self.config.node_alias.clone();
if may_announce_channel(&self.config).is_ok() {
cancellable_background_tasks.spawn_on(async move {
self.runtime.spawn_cancellable_background_task(async move {
// We check every 30 secs whether our last broadcast is NODE_ANN_BCAST_INTERVAL away.
#[cfg(not(test))]
let mut interval = tokio::time::interval(Duration::from_secs(30));
Expand DownExpand Up@@ -498,15 +482,14 @@ impl Node {
}
}
}
}, runtime_handle);
});
}

let stop_tx_bcast = self.stop_sender.subscribe();
let chain_source = Arc::clone(&self.chain_source);
cancellable_background_tasks.spawn_on(
async move { chain_source.continuously_process_broadcast_queue(stop_tx_bcast).await },
runtime_handle,
);
self.runtime.spawn_cancellable_background_task(async move {
chain_source.continuously_process_broadcast_queue(stop_tx_bcast).await
});

let bump_tx_event_handler = Arc::new(BumpTransactionEventHandler::new(
Arc::clone(&self.tx_broadcaster),
Expand DownExpand Up@@ -563,7 +546,7 @@ impl Node {
})
};

let handle = self.runtime.spawn(async move {
self.runtime.spawn_background_processor_task(async move {
process_events_async(
background_persister,
|e| background_event_handler.handle_event(e),
Expand All@@ -584,38 +567,27 @@ impl Node {
panic!("Failed to process events");
});
});
debug_assert!(self.background_processor_task.lock().unwrap().is_none());
*self.background_processor_task.lock().unwrap() = Some(handle);

if let Some(liquidity_source) = self.liquidity_source.as_ref() {
let mut stop_liquidity_handler = self.stop_sender.subscribe();
let liquidity_handler = Arc::clone(&liquidity_source);
let liquidity_logger = Arc::clone(&self.logger);
background_tasks.spawn_on(
async move {
loop {
tokio::select! {
_ = stop_liquidity_handler.changed() => {
log_debug!(
liquidity_logger,
"Stopping processing liquidity events.",
);
return;
}
_ = liquidity_handler.handle_next_event() => {}
self.runtime.spawn_background_task(async move {
loop {
tokio::select! {
_ = stop_liquidity_handler.changed() => {
log_debug!(
liquidity_logger,
"Stopping processing liquidity events.",
);
return;
}
_ = liquidity_handler.handle_next_event() => {}
}
},
runtime_handle,
);
}
});
}

debug_assert!(self.background_tasks.lock().unwrap().is_none());
*self.background_tasks.lock().unwrap() = Some(background_tasks);

debug_assert!(self.cancellable_background_tasks.lock().unwrap().is_none());
*self.cancellable_background_tasks.lock().unwrap() = Some(cancellable_background_tasks);

log_info!(self.logger, "Startup complete.");
*is_running_lock = true;
Ok(())
Expand DownExpand Up@@ -649,15 +621,7 @@ impl Node {
}

// Cancel cancellable background tasks
if let Some(mut tasks) = self.cancellable_background_tasks.lock().unwrap().take() {
let runtime_handle = self.runtime.handle();
tasks.abort_all();
tokio::task::block_in_place(move || {
runtime_handle.block_on(async { while let Some(_) = tasks.join_next().await {} })
});
} else {
debug_assert!(false, "Expected some cancellable background tasks");
};
self.runtime.abort_cancellable_background_tasks();

// Disconnect all peers.
self.peer_manager.disconnect_all_peers();
Expand All@@ -668,91 +632,13 @@ impl Node {
log_debug!(self.logger, "Stopped chain sources.");

// Wait until non-cancellable background tasks (mod LDK's background processor) are done.
let runtime_handle = self.runtime.handle();
if let Some(mut tasks) = self.background_tasks.lock().unwrap().take() {
tokio::task::block_in_place(move || {
runtime_handle.block_on(async {
loop {
let timeout_fut = tokio::time::timeout(
Duration::from_secs(BACKGROUND_TASK_SHUTDOWN_TIMEOUT_SECS),
tasks.join_next_with_id(),
);
match timeout_fut.await {
Ok(Some(Ok((id, _)))) => {
log_trace!(self.logger, "Stopped background task with id {}", id);
},
Ok(Some(Err(e))) => {
tasks.abort_all();
log_trace!(self.logger, "Stopping background task failed: {}", e);
break;
},
Ok(None) => {
log_debug!(self.logger, "Stopped all background tasks");
break;
},
Err(e) => {
tasks.abort_all();
log_error!(
self.logger,
"Stopping background task timed out: {}",
e
);
break;
},
}
}
})
});
} else {
debug_assert!(false, "Expected some background tasks");
};
self.runtime.wait_on_background_tasks();

// Wait until background processing stopped, at least until a timeout is reached.
if let Some(background_processor_task) =
self.background_processor_task.lock().unwrap().take()
{
let abort_handle = background_processor_task.abort_handle();
let timeout_res = tokio::task::block_in_place(move || {
self.runtime.block_on(async {
tokio::time::timeout(
Duration::from_secs(LDK_EVENT_HANDLER_SHUTDOWN_TIMEOUT_SECS),
background_processor_task,
)
.await
})
});

match timeout_res {
Ok(stop_res) => match stop_res {
Ok(()) => log_debug!(self.logger, "Stopped background processing of events."),
Err(e) => {
abort_handle.abort();
log_error!(
self.logger,
"Stopping event handling failed. This should never happen: {}",
e
);
panic!("Stopping event handling failed. This should never happen.");
},
},
Err(e) => {
abort_handle.abort();
log_error!(self.logger, "Stopping event handling timed out: {}", e);
},
}
} else {
debug_assert!(false, "Expected a background processing task");
};
// Finally, wait until background processing stopped, at least until a timeout is reached.
self.runtime.wait_on_background_processor_task();

#[cfg(tokio_unstable)]
{
let runtime_handle = self.runtime.handle();
log_trace!(
self.logger,
"Active runtime tasks left prior to shutdown: {}",
runtime_handle.metrics().active_tasks_count()
);
}
self.runtime.log_metrics();

log_info!(self.logger, "Shutdown complete.");
*is_running_lock = false;
Expand Down
Loading
Loading