From 91bce83d3d6742c92a33ca0e90d77e7235f291ed Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Thu, 31 Jul 2025 01:37:18 +0000 Subject: [PATCH] Do an initial poll of the `ChannelManager` write future immediately In 7d856fe5b05d69b301fdb8a48352f3f3a16efca9 we moved to doing all of our persistence operations in the (async) background processor in parallel. This is great for slow persistence operations (eg with remote persistence). However, the `ChannelManager` persistence is very latency-sensitive (delays may lead to accidental force-closures today) and thus we don't really want to wait on network graph pruning or scorer time-stepping (which can be somewhat slow). Instead, we keep the new bulk-polling of the persistence operations but immediately do a single step of the `ChannelManager` persistence future after it is created. This should give it a chance to get going - initializing whatever network sends or connections need to happen - before we get busy doing CPU-intensive stuff. While it may not actually make the persist happen in full, it at least gives it a chance, and should make as much progress as possible until a network resources is exhausted (eg send buffer is full), at which point we need to wait on the network which is almost certainly slow than the 1ms or so it will take to time-step the scorer. --- lightning-background-processor/src/lib.rs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/lightning-background-processor/src/lib.rs b/lightning-background-processor/src/lib.rs index f53023a0635..1ff0926f9db 100644 --- a/lightning-background-processor/src/lib.rs +++ b/lightning-background-processor/src/lib.rs @@ -482,6 +482,9 @@ pub(crate) mod futures_util { pub(crate) fn set_a(&mut self, fut: A) { self.a = JoinerResult::Pending(Some(fut)); } + pub(crate) fn set_a_res(&mut self, res: Result<(), E>) { + self.a = JoinerResult::Ready(res); + } pub(crate) fn set_b(&mut self, fut: B) { self.b = JoinerResult::Pending(Some(fut)); } @@ -937,7 +940,20 @@ where .await }; // TODO: Once our MSRV is 1.68 we should be able to drop the Box - futures.set_a(Box::pin(fut)); + let mut fut = Box::pin(fut); + + // Because persisting the ChannelManager is important to avoid accidental + // force-closures, go ahead and poll the future once before we do slightly more + // CPU-intensive tasks in the form of NetworkGraph pruning or scorer time-stepping + // below. This will get it moving but won't block us for too long if the underlying + // future is actually async. + use core::future::Future; + let mut waker = dummy_waker(); + let mut ctx = task::Context::from_waker(&mut waker); + match core::pin::Pin::new(&mut fut).poll(&mut ctx) { + task::Poll::Ready(res) => futures.set_a_res(res), + task::Poll::Pending => futures.set_a(fut), + } log_trace!(logger, "Done persisting ChannelManager."); }