Skip to content
Merged
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
18 changes: 17 additions & 1 deletion lightning-background-processor/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
Expand Down Expand Up @@ -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
Copy link
Contributor

@joostjager joostjager Jul 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this is needed, shouldn't we stay on the safe side and await cm persistence separately? (not include it in the joiner)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think so - time-stepping the scorer takes something on the order of 1ms, so its going to be dwarfed by any network latency anyway. On the flip side, remote persistence may take something like 500ms if we have a bit high internet latency and there's a few RTTs. Thus, parallelizing the persistences across all the cases is really important for overall application latency, but at the same time we want to get things moving quick, so its worth polling once to get network stuff going.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To some extent this is really because we're trying to optimize for two drastically different cases - async persist with a local DB that is 0.5ms away and async persist with a remote VSS store that is 500ms away. But I do think this is basically a free way to optimize for both - there's no real cost to polling once, aside from a bit of extra code, and it lets us get ChannelManager persisted fast but doesn't stall the whole thing on net.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, buying this.

// 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.");
}
Expand Down
Loading