Skip to content

Implement Exponential Backoff for Transient Sync Errors - #588

Merged
tnull merged 1 commit into
lightningdevkit:mainfrom
tosynthegeek:main
Jun 30, 2025
Merged

Implement Exponential Backoff for Transient Sync Errors#588
tnull merged 1 commit into
lightningdevkit:mainfrom
tosynthegeek:main

Conversation

@tosynthegeek

Copy link
Copy Markdown
Contributor

This PR attempts to improve retry in the bitcoind RPC synchronization loop from #587 by replacing the existing linear backoff with a proper exponential backoff strategy. We could also add a maximum delay to prevent excessively long waits, but I am not sure if it would really help.

@ldk-reviews-bot

ldk-reviews-bot commented Jun 26, 2025

Copy link
Copy Markdown

👋 Thanks for assigning @tnull as a reviewer!
I'll wait for their review and will help manage the review process.
Once they submit their review, I'll check if a second reviewer would be helpful.

@tnulltnull left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks!

CI is unhappy though, please check that the code compiles before pushing.

Comment threadsrc/chain/mod.rs Outdated
log_error!(logger, "Failed to synchronize chain listeners: {:?}", e);
tokio::time::sleep(Duration::from_secs(CHAIN_POLLING_INTERVAL_SECS))
.await;
backoff_delay_multiplier += 1;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I don't think we should let the backoff delay grow infinitely. Please include a sane upper bound.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Got it, I am adding a max backoff delay of 300 secs for this

Comment threadsrc/chain/mod.rs Outdated
} else {
log_error!(
logger,
"Failed to synchronize chain listeners: {:?}, e"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This doesn't compile. Also, as discussed elsewhere, we at least need to error out. But technically, we should keep retrying currently as otherwise we'd need to add panic here as permanently being unable to connect to the chain source is an unrecoverable error.

@tosynthegeektosynthegeekJun 28, 2025

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

This doesn't compile. Also, as discussed elsewhere, we at least need to error out. But technically, we should keep retrying currently as otherwise we'd need to add panic here as permanently being unable to connect to the chain source is an unrecoverable error.

@tnull As you suggested that panicking isnt best and not being able to error out I stuck with retrying but with the delay of 300 secs. Exponential backoff from CHAIN_POLLING_INTERVAL_SECS was only introduced for transient errors

@tosynthegeek

Copy link
Copy Markdown
ContributorAuthor

Thanks!

CI is unhappy though, please check that the code compiles before pushing.

Yeah, just saw that, would check it out now..

@tnulltnull left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Please also make sure to always provide rationale for the change in the commit message, and format it properly (heading shouldn't be larger than one line). Feel free to refer to https://cbea.ms/git-commit/ on how to write good commit messages.

Previously, chain synchronization failures would retry immediately
without any delay, which could lead to tight retry loops and high
CPU usage during failures.
This change introduces exponential backoff for transient
errors, starting at 2 seconds and doubling each time up to a maximum
of 300 seconds. Persistent errors also now delay retries by the
maximum backoff duration to prevent rapid loops while maintaining
eventual recovery.
Fixeslightningdevkit#587

@tnulltnull left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks!

@tnull
tnull merged commit 775e0db into lightningdevkit:mainJun 30, 2025
Jolah1 added a commit to Jolah1/ldk-node that referenced this pull request Jun 10, 2026
Previously, the background reconnection task retried every persisted peer
on a fixed 60s interval with no backoff, so an unreachable peer was retried
indefinitely at the same cadence — log spam and wasted work. This became
more visible after lightningdevkit#895 retained peers across force-closes so that
channel_reestablish recovery can run.
Track per-peer reconnect state in ConnectionManager: on failure, double the
retry interval up to PEER_RECONNECTION_MAX_INTERVAL (30 min); on success
(including user-initiated connects), clear the state so a subsequent drop
retries promptly. The 60s tokio::time::interval is kept as the wakeup,
gated per-peer by next_retry_at, since lightningdevkit#588's inline-sleep form does not
generalize to N peers. Backoff state is in-memory and resets on restart —
a fresh post-restart attempt is the correct behavior. State is also
cleared when a peer is removed from the persisted store.
Closeslightningdevkit#918.
Jolah1 added a commit to Jolah1/ldk-node that referenced this pull request Jul 1, 2026
Previously, the background reconnection task retried every persisted peer
on a fixed 60s interval with no backoff, so an unreachable peer was retried
indefinitely at the same cadence — log spam and wasted work. This became
more visible after lightningdevkit#895 retained peers across force-closes so that
channel_reestablish recovery can run.
Track per-peer reconnect state in ConnectionManager: on failure, double the
retry interval up to PEER_RECONNECTION_MAX_INTERVAL (30 min); on success
(including user-initiated connects), clear the state so a subsequent drop
retries promptly. The 60s tokio::time::interval is kept as the wakeup,
gated per-peer by next_retry_at, since lightningdevkit#588's inline-sleep form does not
generalize to N peers. Backoff state is in-memory and resets on restart —
a fresh post-restart attempt is the correct behavior. State is also
cleared when a peer is removed from the persisted store.
Closeslightningdevkit#918.
Jolah1 added a commit to Jolah1/ldk-node that referenced this pull request Jul 9, 2026
Previously, the background reconnection task retried every persisted peer
on a fixed 60s interval with no backoff, so an unreachable peer was retried
indefinitely at the same cadence — log spam and wasted work. This became
more visible after lightningdevkit#895 retained peers across force-closes so that
channel_reestablish recovery can run.
Track per-peer reconnect state in ConnectionManager: on failure, double the
retry interval up to PEER_RECONNECTION_MAX_INTERVAL (30 min); on success
(including user-initiated connects), clear the state so a subsequent drop
retries promptly. The 60s tokio::time::interval is kept as the wakeup,
gated per-peer by next_retry_at, since lightningdevkit#588's inline-sleep form does not
generalize to N peers. Backoff state is in-memory and resets on restart —
a fresh post-restart attempt is the correct behavior. State is also
cleared when a peer is removed from the persisted store.
Closeslightningdevkit#918.
Jolah1 added a commit to Jolah1/ldk-node that referenced this pull request Jul 10, 2026
Previously, the background reconnection task retried every persisted peer
on a fixed 60s interval with no backoff, so an unreachable peer was retried
indefinitely at the same cadence — log spam and wasted work. This became
more visible after lightningdevkit#895 retained peers across force-closes so that
channel_reestablish recovery can run.
Track per-peer reconnect state in ConnectionManager: on failure, double the
retry interval up to PEER_RECONNECTION_MAX_INTERVAL (30 min); on success
(including user-initiated connects), clear the state so a subsequent drop
retries promptly. The 60s tokio::time::interval is kept as the wakeup,
gated per-peer by next_retry_at, since lightningdevkit#588's inline-sleep form does not
generalize to N peers. Backoff state is in-memory and resets on restart —
a fresh post-restart attempt is the correct behavior. State is also
cleared when a peer is removed from the persisted store.
Closeslightningdevkit#918.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@tosynthegeek@ldk-reviews-bot@tnull
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
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;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Implement Exponential Backoff for Transient Sync Errors by tosynthegeek · Pull Request #588 · lightningdevkit/ldk-node · GitHub
Skip to content

Implement Exponential Backoff for Transient Sync Errors - #588

Merged
tnull merged 1 commit into
lightningdevkit:mainfrom
tosynthegeek:main
Jun 30, 2025
Merged

Implement Exponential Backoff for Transient Sync Errors#588
tnull merged 1 commit into
lightningdevkit:mainfrom
tosynthegeek:main

Conversation

@tosynthegeek

Copy link
Copy Markdown
Contributor

This PR attempts to improve retry in the bitcoind RPC synchronization loop from #587 by replacing the existing linear backoff with a proper exponential backoff strategy. We could also add a maximum delay to prevent excessively long waits, but I am not sure if it would really help.

@ldk-reviews-bot

ldk-reviews-bot commented Jun 26, 2025

Copy link
Copy Markdown

👋 Thanks for assigning @tnull as a reviewer!
I'll wait for their review and will help manage the review process.
Once they submit their review, I'll check if a second reviewer would be helpful.

@tnulltnull left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks!

CI is unhappy though, please check that the code compiles before pushing.

Comment threadsrc/chain/mod.rs Outdated
log_error!(logger, "Failed to synchronize chain listeners: {:?}", e);
tokio::time::sleep(Duration::from_secs(CHAIN_POLLING_INTERVAL_SECS))
.await;
backoff_delay_multiplier += 1;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I don't think we should let the backoff delay grow infinitely. Please include a sane upper bound.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Got it, I am adding a max backoff delay of 300 secs for this

Comment threadsrc/chain/mod.rs Outdated
} else {
log_error!(
logger,
"Failed to synchronize chain listeners: {:?}, e"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This doesn't compile. Also, as discussed elsewhere, we at least need to error out. But technically, we should keep retrying currently as otherwise we'd need to add panic here as permanently being unable to connect to the chain source is an unrecoverable error.

@tosynthegeektosynthegeekJun 28, 2025

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

This doesn't compile. Also, as discussed elsewhere, we at least need to error out. But technically, we should keep retrying currently as otherwise we'd need to add panic here as permanently being unable to connect to the chain source is an unrecoverable error.

@tnull As you suggested that panicking isnt best and not being able to error out I stuck with retrying but with the delay of 300 secs. Exponential backoff from CHAIN_POLLING_INTERVAL_SECS was only introduced for transient errors

@tosynthegeek

Copy link
Copy Markdown
ContributorAuthor

Thanks!

CI is unhappy though, please check that the code compiles before pushing.

Yeah, just saw that, would check it out now..

@tnulltnull left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Please also make sure to always provide rationale for the change in the commit message, and format it properly (heading shouldn't be larger than one line). Feel free to refer to https://cbea.ms/git-commit/ on how to write good commit messages.

Previously, chain synchronization failures would retry immediately
without any delay, which could lead to tight retry loops and high
CPU usage during failures.
This change introduces exponential backoff for transient
errors, starting at 2 seconds and doubling each time up to a maximum
of 300 seconds. Persistent errors also now delay retries by the
maximum backoff duration to prevent rapid loops while maintaining
eventual recovery.
Fixeslightningdevkit#587

@tnulltnull left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks!

@tnull
tnull merged commit 775e0db into lightningdevkit:mainJun 30, 2025
Jolah1 added a commit to Jolah1/ldk-node that referenced this pull request Jun 10, 2026
Previously, the background reconnection task retried every persisted peer
on a fixed 60s interval with no backoff, so an unreachable peer was retried
indefinitely at the same cadence — log spam and wasted work. This became
more visible after lightningdevkit#895 retained peers across force-closes so that
channel_reestablish recovery can run.
Track per-peer reconnect state in ConnectionManager: on failure, double the
retry interval up to PEER_RECONNECTION_MAX_INTERVAL (30 min); on success
(including user-initiated connects), clear the state so a subsequent drop
retries promptly. The 60s tokio::time::interval is kept as the wakeup,
gated per-peer by next_retry_at, since lightningdevkit#588's inline-sleep form does not
generalize to N peers. Backoff state is in-memory and resets on restart —
a fresh post-restart attempt is the correct behavior. State is also
cleared when a peer is removed from the persisted store.
Closeslightningdevkit#918.
Jolah1 added a commit to Jolah1/ldk-node that referenced this pull request Jul 1, 2026
Previously, the background reconnection task retried every persisted peer
on a fixed 60s interval with no backoff, so an unreachable peer was retried
indefinitely at the same cadence — log spam and wasted work. This became
more visible after lightningdevkit#895 retained peers across force-closes so that
channel_reestablish recovery can run.
Track per-peer reconnect state in ConnectionManager: on failure, double the
retry interval up to PEER_RECONNECTION_MAX_INTERVAL (30 min); on success
(including user-initiated connects), clear the state so a subsequent drop
retries promptly. The 60s tokio::time::interval is kept as the wakeup,
gated per-peer by next_retry_at, since lightningdevkit#588's inline-sleep form does not
generalize to N peers. Backoff state is in-memory and resets on restart —
a fresh post-restart attempt is the correct behavior. State is also
cleared when a peer is removed from the persisted store.
Closeslightningdevkit#918.
Jolah1 added a commit to Jolah1/ldk-node that referenced this pull request Jul 9, 2026
Previously, the background reconnection task retried every persisted peer
on a fixed 60s interval with no backoff, so an unreachable peer was retried
indefinitely at the same cadence — log spam and wasted work. This became
more visible after lightningdevkit#895 retained peers across force-closes so that
channel_reestablish recovery can run.
Track per-peer reconnect state in ConnectionManager: on failure, double the
retry interval up to PEER_RECONNECTION_MAX_INTERVAL (30 min); on success
(including user-initiated connects), clear the state so a subsequent drop
retries promptly. The 60s tokio::time::interval is kept as the wakeup,
gated per-peer by next_retry_at, since lightningdevkit#588's inline-sleep form does not
generalize to N peers. Backoff state is in-memory and resets on restart —
a fresh post-restart attempt is the correct behavior. State is also
cleared when a peer is removed from the persisted store.
Closeslightningdevkit#918.
Jolah1 added a commit to Jolah1/ldk-node that referenced this pull request Jul 10, 2026
Previously, the background reconnection task retried every persisted peer
on a fixed 60s interval with no backoff, so an unreachable peer was retried
indefinitely at the same cadence — log spam and wasted work. This became
more visible after lightningdevkit#895 retained peers across force-closes so that
channel_reestablish recovery can run.
Track per-peer reconnect state in ConnectionManager: on failure, double the
retry interval up to PEER_RECONNECTION_MAX_INTERVAL (30 min); on success
(including user-initiated connects), clear the state so a subsequent drop
retries promptly. The 60s tokio::time::interval is kept as the wakeup,
gated per-peer by next_retry_at, since lightningdevkit#588's inline-sleep form does not
generalize to N peers. Backoff state is in-memory and resets on restart —
a fresh post-restart attempt is the correct behavior. State is also
cleared when a peer is removed from the persisted store.
Closeslightningdevkit#918.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@tosynthegeek@ldk-reviews-bot@tnull
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Implement Exponential Backoff for Transient Sync Errors by tosynthegeek · Pull Request #588 · lightningdevkit/ldk-node · GitHub
Skip to content

Implement Exponential Backoff for Transient Sync Errors - #588

Merged
tnull merged 1 commit into
lightningdevkit:mainfrom
tosynthegeek:main
Jun 30, 2025
Merged

Implement Exponential Backoff for Transient Sync Errors#588
tnull merged 1 commit into
lightningdevkit:mainfrom
tosynthegeek:main

Conversation

@tosynthegeek

Copy link
Copy Markdown
Contributor

This PR attempts to improve retry in the bitcoind RPC synchronization loop from #587 by replacing the existing linear backoff with a proper exponential backoff strategy. We could also add a maximum delay to prevent excessively long waits, but I am not sure if it would really help.

@ldk-reviews-bot

ldk-reviews-bot commented Jun 26, 2025

Copy link
Copy Markdown

👋 Thanks for assigning @tnull as a reviewer!
I'll wait for their review and will help manage the review process.
Once they submit their review, I'll check if a second reviewer would be helpful.

@tnulltnull left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks!

CI is unhappy though, please check that the code compiles before pushing.

Comment threadsrc/chain/mod.rs Outdated
log_error!(logger, "Failed to synchronize chain listeners: {:?}", e);
tokio::time::sleep(Duration::from_secs(CHAIN_POLLING_INTERVAL_SECS))
.await;
backoff_delay_multiplier += 1;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I don't think we should let the backoff delay grow infinitely. Please include a sane upper bound.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Got it, I am adding a max backoff delay of 300 secs for this

Comment threadsrc/chain/mod.rs Outdated
} else {
log_error!(
logger,
"Failed to synchronize chain listeners: {:?}, e"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This doesn't compile. Also, as discussed elsewhere, we at least need to error out. But technically, we should keep retrying currently as otherwise we'd need to add panic here as permanently being unable to connect to the chain source is an unrecoverable error.

@tosynthegeektosynthegeekJun 28, 2025

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

This doesn't compile. Also, as discussed elsewhere, we at least need to error out. But technically, we should keep retrying currently as otherwise we'd need to add panic here as permanently being unable to connect to the chain source is an unrecoverable error.

@tnull As you suggested that panicking isnt best and not being able to error out I stuck with retrying but with the delay of 300 secs. Exponential backoff from CHAIN_POLLING_INTERVAL_SECS was only introduced for transient errors

@tosynthegeek

Copy link
Copy Markdown
ContributorAuthor

Thanks!

CI is unhappy though, please check that the code compiles before pushing.

Yeah, just saw that, would check it out now..

@tnulltnull left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Please also make sure to always provide rationale for the change in the commit message, and format it properly (heading shouldn't be larger than one line). Feel free to refer to https://cbea.ms/git-commit/ on how to write good commit messages.

Previously, chain synchronization failures would retry immediately
without any delay, which could lead to tight retry loops and high
CPU usage during failures.
This change introduces exponential backoff for transient
errors, starting at 2 seconds and doubling each time up to a maximum
of 300 seconds. Persistent errors also now delay retries by the
maximum backoff duration to prevent rapid loops while maintaining
eventual recovery.
Fixeslightningdevkit#587

@tnulltnull left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks!

@tnull
tnull merged commit 775e0db into lightningdevkit:mainJun 30, 2025
Jolah1 added a commit to Jolah1/ldk-node that referenced this pull request Jun 10, 2026
Previously, the background reconnection task retried every persisted peer
on a fixed 60s interval with no backoff, so an unreachable peer was retried
indefinitely at the same cadence — log spam and wasted work. This became
more visible after lightningdevkit#895 retained peers across force-closes so that
channel_reestablish recovery can run.
Track per-peer reconnect state in ConnectionManager: on failure, double the
retry interval up to PEER_RECONNECTION_MAX_INTERVAL (30 min); on success
(including user-initiated connects), clear the state so a subsequent drop
retries promptly. The 60s tokio::time::interval is kept as the wakeup,
gated per-peer by next_retry_at, since lightningdevkit#588's inline-sleep form does not
generalize to N peers. Backoff state is in-memory and resets on restart —
a fresh post-restart attempt is the correct behavior. State is also
cleared when a peer is removed from the persisted store.
Closeslightningdevkit#918.
Jolah1 added a commit to Jolah1/ldk-node that referenced this pull request Jul 1, 2026
Previously, the background reconnection task retried every persisted peer
on a fixed 60s interval with no backoff, so an unreachable peer was retried
indefinitely at the same cadence — log spam and wasted work. This became
more visible after lightningdevkit#895 retained peers across force-closes so that
channel_reestablish recovery can run.
Track per-peer reconnect state in ConnectionManager: on failure, double the
retry interval up to PEER_RECONNECTION_MAX_INTERVAL (30 min); on success
(including user-initiated connects), clear the state so a subsequent drop
retries promptly. The 60s tokio::time::interval is kept as the wakeup,
gated per-peer by next_retry_at, since lightningdevkit#588's inline-sleep form does not
generalize to N peers. Backoff state is in-memory and resets on restart —
a fresh post-restart attempt is the correct behavior. State is also
cleared when a peer is removed from the persisted store.
Closeslightningdevkit#918.
Jolah1 added a commit to Jolah1/ldk-node that referenced this pull request Jul 9, 2026
Previously, the background reconnection task retried every persisted peer
on a fixed 60s interval with no backoff, so an unreachable peer was retried
indefinitely at the same cadence — log spam and wasted work. This became
more visible after lightningdevkit#895 retained peers across force-closes so that
channel_reestablish recovery can run.
Track per-peer reconnect state in ConnectionManager: on failure, double the
retry interval up to PEER_RECONNECTION_MAX_INTERVAL (30 min); on success
(including user-initiated connects), clear the state so a subsequent drop
retries promptly. The 60s tokio::time::interval is kept as the wakeup,
gated per-peer by next_retry_at, since lightningdevkit#588's inline-sleep form does not
generalize to N peers. Backoff state is in-memory and resets on restart —
a fresh post-restart attempt is the correct behavior. State is also
cleared when a peer is removed from the persisted store.
Closeslightningdevkit#918.
Jolah1 added a commit to Jolah1/ldk-node that referenced this pull request Jul 10, 2026
Previously, the background reconnection task retried every persisted peer
on a fixed 60s interval with no backoff, so an unreachable peer was retried
indefinitely at the same cadence — log spam and wasted work. This became
more visible after lightningdevkit#895 retained peers across force-closes so that
channel_reestablish recovery can run.
Track per-peer reconnect state in ConnectionManager: on failure, double the
retry interval up to PEER_RECONNECTION_MAX_INTERVAL (30 min); on success
(including user-initiated connects), clear the state so a subsequent drop
retries promptly. The 60s tokio::time::interval is kept as the wakeup,
gated per-peer by next_retry_at, since lightningdevkit#588's inline-sleep form does not
generalize to N peers. Backoff state is in-memory and resets on restart —
a fresh post-restart attempt is the correct behavior. State is also
cleared when a peer is removed from the persisted store.
Closeslightningdevkit#918.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@tosynthegeek@ldk-reviews-bot@tnull
, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Implement Exponential Backoff for Transient Sync Errors by tosynthegeek · Pull Request #588 · lightningdevkit/ldk-node · GitHub
Skip to content

Implement Exponential Backoff for Transient Sync Errors - #588

Merged
tnull merged 1 commit into
lightningdevkit:mainfrom
tosynthegeek:main
Jun 30, 2025
Merged

Implement Exponential Backoff for Transient Sync Errors#588
tnull merged 1 commit into
lightningdevkit:mainfrom
tosynthegeek:main

Conversation

@tosynthegeek

Copy link
Copy Markdown
Contributor

This PR attempts to improve retry in the bitcoind RPC synchronization loop from #587 by replacing the existing linear backoff with a proper exponential backoff strategy. We could also add a maximum delay to prevent excessively long waits, but I am not sure if it would really help.

@ldk-reviews-bot

ldk-reviews-bot commented Jun 26, 2025

Copy link
Copy Markdown

👋 Thanks for assigning @tnull as a reviewer!
I'll wait for their review and will help manage the review process.
Once they submit their review, I'll check if a second reviewer would be helpful.

@tnulltnull left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks!

CI is unhappy though, please check that the code compiles before pushing.

Comment threadsrc/chain/mod.rs Outdated
log_error!(logger, "Failed to synchronize chain listeners: {:?}", e);
tokio::time::sleep(Duration::from_secs(CHAIN_POLLING_INTERVAL_SECS))
.await;
backoff_delay_multiplier += 1;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I don't think we should let the backoff delay grow infinitely. Please include a sane upper bound.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Got it, I am adding a max backoff delay of 300 secs for this

Comment threadsrc/chain/mod.rs Outdated
} else {
log_error!(
logger,
"Failed to synchronize chain listeners: {:?}, e"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This doesn't compile. Also, as discussed elsewhere, we at least need to error out. But technically, we should keep retrying currently as otherwise we'd need to add panic here as permanently being unable to connect to the chain source is an unrecoverable error.

@tosynthegeektosynthegeekJun 28, 2025

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

This doesn't compile. Also, as discussed elsewhere, we at least need to error out. But technically, we should keep retrying currently as otherwise we'd need to add panic here as permanently being unable to connect to the chain source is an unrecoverable error.

@tnull As you suggested that panicking isnt best and not being able to error out I stuck with retrying but with the delay of 300 secs. Exponential backoff from CHAIN_POLLING_INTERVAL_SECS was only introduced for transient errors

@tosynthegeek

Copy link
Copy Markdown
ContributorAuthor

Thanks!

CI is unhappy though, please check that the code compiles before pushing.

Yeah, just saw that, would check it out now..

@tnulltnull left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Please also make sure to always provide rationale for the change in the commit message, and format it properly (heading shouldn't be larger than one line). Feel free to refer to https://cbea.ms/git-commit/ on how to write good commit messages.

Previously, chain synchronization failures would retry immediately
without any delay, which could lead to tight retry loops and high
CPU usage during failures.
This change introduces exponential backoff for transient
errors, starting at 2 seconds and doubling each time up to a maximum
of 300 seconds. Persistent errors also now delay retries by the
maximum backoff duration to prevent rapid loops while maintaining
eventual recovery.
Fixeslightningdevkit#587

@tnulltnull left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks!

@tnull
tnull merged commit 775e0db into lightningdevkit:mainJun 30, 2025
Jolah1 added a commit to Jolah1/ldk-node that referenced this pull request Jun 10, 2026
Previously, the background reconnection task retried every persisted peer
on a fixed 60s interval with no backoff, so an unreachable peer was retried
indefinitely at the same cadence — log spam and wasted work. This became
more visible after lightningdevkit#895 retained peers across force-closes so that
channel_reestablish recovery can run.
Track per-peer reconnect state in ConnectionManager: on failure, double the
retry interval up to PEER_RECONNECTION_MAX_INTERVAL (30 min); on success
(including user-initiated connects), clear the state so a subsequent drop
retries promptly. The 60s tokio::time::interval is kept as the wakeup,
gated per-peer by next_retry_at, since lightningdevkit#588's inline-sleep form does not
generalize to N peers. Backoff state is in-memory and resets on restart —
a fresh post-restart attempt is the correct behavior. State is also
cleared when a peer is removed from the persisted store.
Closeslightningdevkit#918.
Jolah1 added a commit to Jolah1/ldk-node that referenced this pull request Jul 1, 2026
Previously, the background reconnection task retried every persisted peer
on a fixed 60s interval with no backoff, so an unreachable peer was retried
indefinitely at the same cadence — log spam and wasted work. This became
more visible after lightningdevkit#895 retained peers across force-closes so that
channel_reestablish recovery can run.
Track per-peer reconnect state in ConnectionManager: on failure, double the
retry interval up to PEER_RECONNECTION_MAX_INTERVAL (30 min); on success
(including user-initiated connects), clear the state so a subsequent drop
retries promptly. The 60s tokio::time::interval is kept as the wakeup,
gated per-peer by next_retry_at, since lightningdevkit#588's inline-sleep form does not
generalize to N peers. Backoff state is in-memory and resets on restart —
a fresh post-restart attempt is the correct behavior. State is also
cleared when a peer is removed from the persisted store.
Closeslightningdevkit#918.
Jolah1 added a commit to Jolah1/ldk-node that referenced this pull request Jul 9, 2026
Previously, the background reconnection task retried every persisted peer
on a fixed 60s interval with no backoff, so an unreachable peer was retried
indefinitely at the same cadence — log spam and wasted work. This became
more visible after lightningdevkit#895 retained peers across force-closes so that
channel_reestablish recovery can run.
Track per-peer reconnect state in ConnectionManager: on failure, double the
retry interval up to PEER_RECONNECTION_MAX_INTERVAL (30 min); on success
(including user-initiated connects), clear the state so a subsequent drop
retries promptly. The 60s tokio::time::interval is kept as the wakeup,
gated per-peer by next_retry_at, since lightningdevkit#588's inline-sleep form does not
generalize to N peers. Backoff state is in-memory and resets on restart —
a fresh post-restart attempt is the correct behavior. State is also
cleared when a peer is removed from the persisted store.
Closeslightningdevkit#918.
Jolah1 added a commit to Jolah1/ldk-node that referenced this pull request Jul 10, 2026
Previously, the background reconnection task retried every persisted peer
on a fixed 60s interval with no backoff, so an unreachable peer was retried
indefinitely at the same cadence — log spam and wasted work. This became
more visible after lightningdevkit#895 retained peers across force-closes so that
channel_reestablish recovery can run.
Track per-peer reconnect state in ConnectionManager: on failure, double the
retry interval up to PEER_RECONNECTION_MAX_INTERVAL (30 min); on success
(including user-initiated connects), clear the state so a subsequent drop
retries promptly. The 60s tokio::time::interval is kept as the wakeup,
gated per-peer by next_retry_at, since lightningdevkit#588's inline-sleep form does not
generalize to N peers. Backoff state is in-memory and resets on restart —
a fresh post-restart attempt is the correct behavior. State is also
cleared when a peer is removed from the persisted store.
Closeslightningdevkit#918.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@tosynthegeek@ldk-reviews-bot@tnull
, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' Implement Exponential Backoff for Transient Sync Errors by tosynthegeek · Pull Request #588 · lightningdevkit/ldk-node · GitHub
Skip to content

Implement Exponential Backoff for Transient Sync Errors - #588

Merged
tnull merged 1 commit into
lightningdevkit:mainfrom
tosynthegeek:main
Jun 30, 2025
Merged

Implement Exponential Backoff for Transient Sync Errors#588
tnull merged 1 commit into
lightningdevkit:mainfrom
tosynthegeek:main

Conversation

@tosynthegeek

Copy link
Copy Markdown
Contributor

This PR attempts to improve retry in the bitcoind RPC synchronization loop from #587 by replacing the existing linear backoff with a proper exponential backoff strategy. We could also add a maximum delay to prevent excessively long waits, but I am not sure if it would really help.

@ldk-reviews-bot

ldk-reviews-bot commented Jun 26, 2025

Copy link
Copy Markdown

👋 Thanks for assigning @tnull as a reviewer!
I'll wait for their review and will help manage the review process.
Once they submit their review, I'll check if a second reviewer would be helpful.

@tnulltnull left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks!

CI is unhappy though, please check that the code compiles before pushing.

Comment threadsrc/chain/mod.rs Outdated
log_error!(logger, "Failed to synchronize chain listeners: {:?}", e);
tokio::time::sleep(Duration::from_secs(CHAIN_POLLING_INTERVAL_SECS))
.await;
backoff_delay_multiplier += 1;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I don't think we should let the backoff delay grow infinitely. Please include a sane upper bound.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Got it, I am adding a max backoff delay of 300 secs for this

Comment threadsrc/chain/mod.rs Outdated
} else {
log_error!(
logger,
"Failed to synchronize chain listeners: {:?}, e"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This doesn't compile. Also, as discussed elsewhere, we at least need to error out. But technically, we should keep retrying currently as otherwise we'd need to add panic here as permanently being unable to connect to the chain source is an unrecoverable error.

@tosynthegeektosynthegeekJun 28, 2025

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

This doesn't compile. Also, as discussed elsewhere, we at least need to error out. But technically, we should keep retrying currently as otherwise we'd need to add panic here as permanently being unable to connect to the chain source is an unrecoverable error.

@tnull As you suggested that panicking isnt best and not being able to error out I stuck with retrying but with the delay of 300 secs. Exponential backoff from CHAIN_POLLING_INTERVAL_SECS was only introduced for transient errors

@tosynthegeek

Copy link
Copy Markdown
ContributorAuthor

Thanks!

CI is unhappy though, please check that the code compiles before pushing.

Yeah, just saw that, would check it out now..

@tnulltnull left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Please also make sure to always provide rationale for the change in the commit message, and format it properly (heading shouldn't be larger than one line). Feel free to refer to https://cbea.ms/git-commit/ on how to write good commit messages.

Previously, chain synchronization failures would retry immediately
without any delay, which could lead to tight retry loops and high
CPU usage during failures.
This change introduces exponential backoff for transient
errors, starting at 2 seconds and doubling each time up to a maximum
of 300 seconds. Persistent errors also now delay retries by the
maximum backoff duration to prevent rapid loops while maintaining
eventual recovery.
Fixeslightningdevkit#587

@tnulltnull left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks!

@tnull
tnull merged commit 775e0db into lightningdevkit:mainJun 30, 2025
Jolah1 added a commit to Jolah1/ldk-node that referenced this pull request Jun 10, 2026
Previously, the background reconnection task retried every persisted peer
on a fixed 60s interval with no backoff, so an unreachable peer was retried
indefinitely at the same cadence — log spam and wasted work. This became
more visible after lightningdevkit#895 retained peers across force-closes so that
channel_reestablish recovery can run.
Track per-peer reconnect state in ConnectionManager: on failure, double the
retry interval up to PEER_RECONNECTION_MAX_INTERVAL (30 min); on success
(including user-initiated connects), clear the state so a subsequent drop
retries promptly. The 60s tokio::time::interval is kept as the wakeup,
gated per-peer by next_retry_at, since lightningdevkit#588's inline-sleep form does not
generalize to N peers. Backoff state is in-memory and resets on restart —
a fresh post-restart attempt is the correct behavior. State is also
cleared when a peer is removed from the persisted store.
Closeslightningdevkit#918.
Jolah1 added a commit to Jolah1/ldk-node that referenced this pull request Jul 1, 2026
Previously, the background reconnection task retried every persisted peer
on a fixed 60s interval with no backoff, so an unreachable peer was retried
indefinitely at the same cadence — log spam and wasted work. This became
more visible after lightningdevkit#895 retained peers across force-closes so that
channel_reestablish recovery can run.
Track per-peer reconnect state in ConnectionManager: on failure, double the
retry interval up to PEER_RECONNECTION_MAX_INTERVAL (30 min); on success
(including user-initiated connects), clear the state so a subsequent drop
retries promptly. The 60s tokio::time::interval is kept as the wakeup,
gated per-peer by next_retry_at, since lightningdevkit#588's inline-sleep form does not
generalize to N peers. Backoff state is in-memory and resets on restart —
a fresh post-restart attempt is the correct behavior. State is also
cleared when a peer is removed from the persisted store.
Closeslightningdevkit#918.
Jolah1 added a commit to Jolah1/ldk-node that referenced this pull request Jul 9, 2026
Previously, the background reconnection task retried every persisted peer
on a fixed 60s interval with no backoff, so an unreachable peer was retried
indefinitely at the same cadence — log spam and wasted work. This became
more visible after lightningdevkit#895 retained peers across force-closes so that
channel_reestablish recovery can run.
Track per-peer reconnect state in ConnectionManager: on failure, double the
retry interval up to PEER_RECONNECTION_MAX_INTERVAL (30 min); on success
(including user-initiated connects), clear the state so a subsequent drop
retries promptly. The 60s tokio::time::interval is kept as the wakeup,
gated per-peer by next_retry_at, since lightningdevkit#588's inline-sleep form does not
generalize to N peers. Backoff state is in-memory and resets on restart —
a fresh post-restart attempt is the correct behavior. State is also
cleared when a peer is removed from the persisted store.
Closeslightningdevkit#918.
Jolah1 added a commit to Jolah1/ldk-node that referenced this pull request Jul 10, 2026
Previously, the background reconnection task retried every persisted peer
on a fixed 60s interval with no backoff, so an unreachable peer was retried
indefinitely at the same cadence — log spam and wasted work. This became
more visible after lightningdevkit#895 retained peers across force-closes so that
channel_reestablish recovery can run.
Track per-peer reconnect state in ConnectionManager: on failure, double the
retry interval up to PEER_RECONNECTION_MAX_INTERVAL (30 min); on success
(including user-initiated connects), clear the state so a subsequent drop
retries promptly. The 60s tokio::time::interval is kept as the wakeup,
gated per-peer by next_retry_at, since lightningdevkit#588's inline-sleep form does not
generalize to N peers. Backoff state is in-memory and resets on restart —
a fresh post-restart attempt is the correct behavior. State is also
cleared when a peer is removed from the persisted store.
Closeslightningdevkit#918.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@tosynthegeek@ldk-reviews-bot@tnull
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Implement Exponential Backoff for Transient Sync Errors by tosynthegeek · Pull Request #588 · lightningdevkit/ldk-node · GitHub
Skip to content

Implement Exponential Backoff for Transient Sync Errors - #588

Merged
tnull merged 1 commit into
lightningdevkit:mainfrom
tosynthegeek:main
Jun 30, 2025
Merged

Implement Exponential Backoff for Transient Sync Errors#588
tnull merged 1 commit into
lightningdevkit:mainfrom
tosynthegeek:main

Conversation

@tosynthegeek

Copy link
Copy Markdown
Contributor

This PR attempts to improve retry in the bitcoind RPC synchronization loop from #587 by replacing the existing linear backoff with a proper exponential backoff strategy. We could also add a maximum delay to prevent excessively long waits, but I am not sure if it would really help.

@ldk-reviews-bot

ldk-reviews-bot commented Jun 26, 2025

Copy link
Copy Markdown

👋 Thanks for assigning @tnull as a reviewer!
I'll wait for their review and will help manage the review process.
Once they submit their review, I'll check if a second reviewer would be helpful.

@tnulltnull left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks!

CI is unhappy though, please check that the code compiles before pushing.

Comment threadsrc/chain/mod.rs Outdated
log_error!(logger, "Failed to synchronize chain listeners: {:?}", e);
tokio::time::sleep(Duration::from_secs(CHAIN_POLLING_INTERVAL_SECS))
.await;
backoff_delay_multiplier += 1;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I don't think we should let the backoff delay grow infinitely. Please include a sane upper bound.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Got it, I am adding a max backoff delay of 300 secs for this

Comment threadsrc/chain/mod.rs Outdated
} else {
log_error!(
logger,
"Failed to synchronize chain listeners: {:?}, e"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This doesn't compile. Also, as discussed elsewhere, we at least need to error out. But technically, we should keep retrying currently as otherwise we'd need to add panic here as permanently being unable to connect to the chain source is an unrecoverable error.

@tosynthegeektosynthegeekJun 28, 2025

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

This doesn't compile. Also, as discussed elsewhere, we at least need to error out. But technically, we should keep retrying currently as otherwise we'd need to add panic here as permanently being unable to connect to the chain source is an unrecoverable error.

@tnull As you suggested that panicking isnt best and not being able to error out I stuck with retrying but with the delay of 300 secs. Exponential backoff from CHAIN_POLLING_INTERVAL_SECS was only introduced for transient errors

@tosynthegeek

Copy link
Copy Markdown
ContributorAuthor

Thanks!

CI is unhappy though, please check that the code compiles before pushing.

Yeah, just saw that, would check it out now..

@tnulltnull left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Please also make sure to always provide rationale for the change in the commit message, and format it properly (heading shouldn't be larger than one line). Feel free to refer to https://cbea.ms/git-commit/ on how to write good commit messages.

Previously, chain synchronization failures would retry immediately
without any delay, which could lead to tight retry loops and high
CPU usage during failures.
This change introduces exponential backoff for transient
errors, starting at 2 seconds and doubling each time up to a maximum
of 300 seconds. Persistent errors also now delay retries by the
maximum backoff duration to prevent rapid loops while maintaining
eventual recovery.
Fixeslightningdevkit#587

@tnulltnull left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks!

@tnull
tnull merged commit 775e0db into lightningdevkit:mainJun 30, 2025
Jolah1 added a commit to Jolah1/ldk-node that referenced this pull request Jun 10, 2026
Previously, the background reconnection task retried every persisted peer
on a fixed 60s interval with no backoff, so an unreachable peer was retried
indefinitely at the same cadence — log spam and wasted work. This became
more visible after lightningdevkit#895 retained peers across force-closes so that
channel_reestablish recovery can run.
Track per-peer reconnect state in ConnectionManager: on failure, double the
retry interval up to PEER_RECONNECTION_MAX_INTERVAL (30 min); on success
(including user-initiated connects), clear the state so a subsequent drop
retries promptly. The 60s tokio::time::interval is kept as the wakeup,
gated per-peer by next_retry_at, since lightningdevkit#588's inline-sleep form does not
generalize to N peers. Backoff state is in-memory and resets on restart —
a fresh post-restart attempt is the correct behavior. State is also
cleared when a peer is removed from the persisted store.
Closeslightningdevkit#918.
Jolah1 added a commit to Jolah1/ldk-node that referenced this pull request Jul 1, 2026
Previously, the background reconnection task retried every persisted peer
on a fixed 60s interval with no backoff, so an unreachable peer was retried
indefinitely at the same cadence — log spam and wasted work. This became
more visible after lightningdevkit#895 retained peers across force-closes so that
channel_reestablish recovery can run.
Track per-peer reconnect state in ConnectionManager: on failure, double the
retry interval up to PEER_RECONNECTION_MAX_INTERVAL (30 min); on success
(including user-initiated connects), clear the state so a subsequent drop
retries promptly. The 60s tokio::time::interval is kept as the wakeup,
gated per-peer by next_retry_at, since lightningdevkit#588's inline-sleep form does not
generalize to N peers. Backoff state is in-memory and resets on restart —
a fresh post-restart attempt is the correct behavior. State is also
cleared when a peer is removed from the persisted store.
Closeslightningdevkit#918.
Jolah1 added a commit to Jolah1/ldk-node that referenced this pull request Jul 9, 2026
Previously, the background reconnection task retried every persisted peer
on a fixed 60s interval with no backoff, so an unreachable peer was retried
indefinitely at the same cadence — log spam and wasted work. This became
more visible after lightningdevkit#895 retained peers across force-closes so that
channel_reestablish recovery can run.
Track per-peer reconnect state in ConnectionManager: on failure, double the
retry interval up to PEER_RECONNECTION_MAX_INTERVAL (30 min); on success
(including user-initiated connects), clear the state so a subsequent drop
retries promptly. The 60s tokio::time::interval is kept as the wakeup,
gated per-peer by next_retry_at, since lightningdevkit#588's inline-sleep form does not
generalize to N peers. Backoff state is in-memory and resets on restart —
a fresh post-restart attempt is the correct behavior. State is also
cleared when a peer is removed from the persisted store.
Closeslightningdevkit#918.
Jolah1 added a commit to Jolah1/ldk-node that referenced this pull request Jul 10, 2026
Previously, the background reconnection task retried every persisted peer
on a fixed 60s interval with no backoff, so an unreachable peer was retried
indefinitely at the same cadence — log spam and wasted work. This became
more visible after lightningdevkit#895 retained peers across force-closes so that
channel_reestablish recovery can run.
Track per-peer reconnect state in ConnectionManager: on failure, double the
retry interval up to PEER_RECONNECTION_MAX_INTERVAL (30 min); on success
(including user-initiated connects), clear the state so a subsequent drop
retries promptly. The 60s tokio::time::interval is kept as the wakeup,
gated per-peer by next_retry_at, since lightningdevkit#588's inline-sleep form does not
generalize to N peers. Backoff state is in-memory and resets on restart —
a fresh post-restart attempt is the correct behavior. State is also
cleared when a peer is removed from the persisted store.
Closeslightningdevkit#918.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@tosynthegeek@ldk-reviews-bot@tnull
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Implement Exponential Backoff for Transient Sync Errors by tosynthegeek · Pull Request #588 · lightningdevkit/ldk-node · GitHub
Skip to content

Implement Exponential Backoff for Transient Sync Errors - #588

Merged
tnull merged 1 commit into
lightningdevkit:mainfrom
tosynthegeek:main
Jun 30, 2025
Merged

Implement Exponential Backoff for Transient Sync Errors#588
tnull merged 1 commit into
lightningdevkit:mainfrom
tosynthegeek:main

Conversation

@tosynthegeek

Copy link
Copy Markdown
Contributor

This PR attempts to improve retry in the bitcoind RPC synchronization loop from #587 by replacing the existing linear backoff with a proper exponential backoff strategy. We could also add a maximum delay to prevent excessively long waits, but I am not sure if it would really help.

@ldk-reviews-bot

ldk-reviews-bot commented Jun 26, 2025

Copy link
Copy Markdown

👋 Thanks for assigning @tnull as a reviewer!
I'll wait for their review and will help manage the review process.
Once they submit their review, I'll check if a second reviewer would be helpful.

@tnulltnull left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks!

CI is unhappy though, please check that the code compiles before pushing.

Comment threadsrc/chain/mod.rs Outdated
log_error!(logger, "Failed to synchronize chain listeners: {:?}", e);
tokio::time::sleep(Duration::from_secs(CHAIN_POLLING_INTERVAL_SECS))
.await;
backoff_delay_multiplier += 1;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I don't think we should let the backoff delay grow infinitely. Please include a sane upper bound.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Got it, I am adding a max backoff delay of 300 secs for this

Comment threadsrc/chain/mod.rs Outdated
} else {
log_error!(
logger,
"Failed to synchronize chain listeners: {:?}, e"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This doesn't compile. Also, as discussed elsewhere, we at least need to error out. But technically, we should keep retrying currently as otherwise we'd need to add panic here as permanently being unable to connect to the chain source is an unrecoverable error.

@tosynthegeektosynthegeekJun 28, 2025

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

This doesn't compile. Also, as discussed elsewhere, we at least need to error out. But technically, we should keep retrying currently as otherwise we'd need to add panic here as permanently being unable to connect to the chain source is an unrecoverable error.

@tnull As you suggested that panicking isnt best and not being able to error out I stuck with retrying but with the delay of 300 secs. Exponential backoff from CHAIN_POLLING_INTERVAL_SECS was only introduced for transient errors

@tosynthegeek

Copy link
Copy Markdown
ContributorAuthor

Thanks!

CI is unhappy though, please check that the code compiles before pushing.

Yeah, just saw that, would check it out now..

@tnulltnull left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Please also make sure to always provide rationale for the change in the commit message, and format it properly (heading shouldn't be larger than one line). Feel free to refer to https://cbea.ms/git-commit/ on how to write good commit messages.

Previously, chain synchronization failures would retry immediately
without any delay, which could lead to tight retry loops and high
CPU usage during failures.
This change introduces exponential backoff for transient
errors, starting at 2 seconds and doubling each time up to a maximum
of 300 seconds. Persistent errors also now delay retries by the
maximum backoff duration to prevent rapid loops while maintaining
eventual recovery.
Fixeslightningdevkit#587

@tnulltnull left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks!

@tnull
tnull merged commit 775e0db into lightningdevkit:mainJun 30, 2025
Jolah1 added a commit to Jolah1/ldk-node that referenced this pull request Jun 10, 2026
Previously, the background reconnection task retried every persisted peer
on a fixed 60s interval with no backoff, so an unreachable peer was retried
indefinitely at the same cadence — log spam and wasted work. This became
more visible after lightningdevkit#895 retained peers across force-closes so that
channel_reestablish recovery can run.
Track per-peer reconnect state in ConnectionManager: on failure, double the
retry interval up to PEER_RECONNECTION_MAX_INTERVAL (30 min); on success
(including user-initiated connects), clear the state so a subsequent drop
retries promptly. The 60s tokio::time::interval is kept as the wakeup,
gated per-peer by next_retry_at, since lightningdevkit#588's inline-sleep form does not
generalize to N peers. Backoff state is in-memory and resets on restart —
a fresh post-restart attempt is the correct behavior. State is also
cleared when a peer is removed from the persisted store.
Closeslightningdevkit#918.
Jolah1 added a commit to Jolah1/ldk-node that referenced this pull request Jul 1, 2026
Previously, the background reconnection task retried every persisted peer
on a fixed 60s interval with no backoff, so an unreachable peer was retried
indefinitely at the same cadence — log spam and wasted work. This became
more visible after lightningdevkit#895 retained peers across force-closes so that
channel_reestablish recovery can run.
Track per-peer reconnect state in ConnectionManager: on failure, double the
retry interval up to PEER_RECONNECTION_MAX_INTERVAL (30 min); on success
(including user-initiated connects), clear the state so a subsequent drop
retries promptly. The 60s tokio::time::interval is kept as the wakeup,
gated per-peer by next_retry_at, since lightningdevkit#588's inline-sleep form does not
generalize to N peers. Backoff state is in-memory and resets on restart —
a fresh post-restart attempt is the correct behavior. State is also
cleared when a peer is removed from the persisted store.
Closeslightningdevkit#918.
Jolah1 added a commit to Jolah1/ldk-node that referenced this pull request Jul 9, 2026
Previously, the background reconnection task retried every persisted peer
on a fixed 60s interval with no backoff, so an unreachable peer was retried
indefinitely at the same cadence — log spam and wasted work. This became
more visible after lightningdevkit#895 retained peers across force-closes so that
channel_reestablish recovery can run.
Track per-peer reconnect state in ConnectionManager: on failure, double the
retry interval up to PEER_RECONNECTION_MAX_INTERVAL (30 min); on success
(including user-initiated connects), clear the state so a subsequent drop
retries promptly. The 60s tokio::time::interval is kept as the wakeup,
gated per-peer by next_retry_at, since lightningdevkit#588's inline-sleep form does not
generalize to N peers. Backoff state is in-memory and resets on restart —
a fresh post-restart attempt is the correct behavior. State is also
cleared when a peer is removed from the persisted store.
Closeslightningdevkit#918.
Jolah1 added a commit to Jolah1/ldk-node that referenced this pull request Jul 10, 2026
Previously, the background reconnection task retried every persisted peer
on a fixed 60s interval with no backoff, so an unreachable peer was retried
indefinitely at the same cadence — log spam and wasted work. This became
more visible after lightningdevkit#895 retained peers across force-closes so that
channel_reestablish recovery can run.
Track per-peer reconnect state in ConnectionManager: on failure, double the
retry interval up to PEER_RECONNECTION_MAX_INTERVAL (30 min); on success
(including user-initiated connects), clear the state so a subsequent drop
retries promptly. The 60s tokio::time::interval is kept as the wakeup,
gated per-peer by next_retry_at, since lightningdevkit#588's inline-sleep form does not
generalize to N peers. Backoff state is in-memory and resets on restart —
a fresh post-restart attempt is the correct behavior. State is also
cleared when a peer is removed from the persisted store.
Closeslightningdevkit#918.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@tosynthegeek@ldk-reviews-bot@tnull
, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })(); Implement Exponential Backoff for Transient Sync Errors by tosynthegeek · Pull Request #588 · lightningdevkit/ldk-node · GitHub
Skip to content

Implement Exponential Backoff for Transient Sync Errors - #588

Merged
tnull merged 1 commit into
lightningdevkit:mainfrom
tosynthegeek:main
Jun 30, 2025
Merged

Implement Exponential Backoff for Transient Sync Errors#588
tnull merged 1 commit into
lightningdevkit:mainfrom
tosynthegeek:main

Conversation

@tosynthegeek

Copy link
Copy Markdown
Contributor

This PR attempts to improve retry in the bitcoind RPC synchronization loop from #587 by replacing the existing linear backoff with a proper exponential backoff strategy. We could also add a maximum delay to prevent excessively long waits, but I am not sure if it would really help.

@ldk-reviews-bot

ldk-reviews-bot commented Jun 26, 2025

Copy link
Copy Markdown

👋 Thanks for assigning @tnull as a reviewer!
I'll wait for their review and will help manage the review process.
Once they submit their review, I'll check if a second reviewer would be helpful.

@tnulltnull left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks!

CI is unhappy though, please check that the code compiles before pushing.

Comment threadsrc/chain/mod.rs Outdated
log_error!(logger, "Failed to synchronize chain listeners: {:?}", e);
tokio::time::sleep(Duration::from_secs(CHAIN_POLLING_INTERVAL_SECS))
.await;
backoff_delay_multiplier += 1;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I don't think we should let the backoff delay grow infinitely. Please include a sane upper bound.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Got it, I am adding a max backoff delay of 300 secs for this

Comment threadsrc/chain/mod.rs Outdated
} else {
log_error!(
logger,
"Failed to synchronize chain listeners: {:?}, e"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This doesn't compile. Also, as discussed elsewhere, we at least need to error out. But technically, we should keep retrying currently as otherwise we'd need to add panic here as permanently being unable to connect to the chain source is an unrecoverable error.

@tosynthegeektosynthegeekJun 28, 2025

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

This doesn't compile. Also, as discussed elsewhere, we at least need to error out. But technically, we should keep retrying currently as otherwise we'd need to add panic here as permanently being unable to connect to the chain source is an unrecoverable error.

@tnull As you suggested that panicking isnt best and not being able to error out I stuck with retrying but with the delay of 300 secs. Exponential backoff from CHAIN_POLLING_INTERVAL_SECS was only introduced for transient errors

@tosynthegeek

Copy link
Copy Markdown
ContributorAuthor

Thanks!

CI is unhappy though, please check that the code compiles before pushing.

Yeah, just saw that, would check it out now..

@tnulltnull left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Please also make sure to always provide rationale for the change in the commit message, and format it properly (heading shouldn't be larger than one line). Feel free to refer to https://cbea.ms/git-commit/ on how to write good commit messages.

Previously, chain synchronization failures would retry immediately
without any delay, which could lead to tight retry loops and high
CPU usage during failures.
This change introduces exponential backoff for transient
errors, starting at 2 seconds and doubling each time up to a maximum
of 300 seconds. Persistent errors also now delay retries by the
maximum backoff duration to prevent rapid loops while maintaining
eventual recovery.
Fixeslightningdevkit#587

@tnulltnull left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks!

@tnull
tnull merged commit 775e0db into lightningdevkit:mainJun 30, 2025
Jolah1 added a commit to Jolah1/ldk-node that referenced this pull request Jun 10, 2026
Previously, the background reconnection task retried every persisted peer
on a fixed 60s interval with no backoff, so an unreachable peer was retried
indefinitely at the same cadence — log spam and wasted work. This became
more visible after lightningdevkit#895 retained peers across force-closes so that
channel_reestablish recovery can run.
Track per-peer reconnect state in ConnectionManager: on failure, double the
retry interval up to PEER_RECONNECTION_MAX_INTERVAL (30 min); on success
(including user-initiated connects), clear the state so a subsequent drop
retries promptly. The 60s tokio::time::interval is kept as the wakeup,
gated per-peer by next_retry_at, since lightningdevkit#588's inline-sleep form does not
generalize to N peers. Backoff state is in-memory and resets on restart —
a fresh post-restart attempt is the correct behavior. State is also
cleared when a peer is removed from the persisted store.
Closeslightningdevkit#918.
Jolah1 added a commit to Jolah1/ldk-node that referenced this pull request Jul 1, 2026
Previously, the background reconnection task retried every persisted peer
on a fixed 60s interval with no backoff, so an unreachable peer was retried
indefinitely at the same cadence — log spam and wasted work. This became
more visible after lightningdevkit#895 retained peers across force-closes so that
channel_reestablish recovery can run.
Track per-peer reconnect state in ConnectionManager: on failure, double the
retry interval up to PEER_RECONNECTION_MAX_INTERVAL (30 min); on success
(including user-initiated connects), clear the state so a subsequent drop
retries promptly. The 60s tokio::time::interval is kept as the wakeup,
gated per-peer by next_retry_at, since lightningdevkit#588's inline-sleep form does not
generalize to N peers. Backoff state is in-memory and resets on restart —
a fresh post-restart attempt is the correct behavior. State is also
cleared when a peer is removed from the persisted store.
Closeslightningdevkit#918.
Jolah1 added a commit to Jolah1/ldk-node that referenced this pull request Jul 9, 2026
Previously, the background reconnection task retried every persisted peer
on a fixed 60s interval with no backoff, so an unreachable peer was retried
indefinitely at the same cadence — log spam and wasted work. This became
more visible after lightningdevkit#895 retained peers across force-closes so that
channel_reestablish recovery can run.
Track per-peer reconnect state in ConnectionManager: on failure, double the
retry interval up to PEER_RECONNECTION_MAX_INTERVAL (30 min); on success
(including user-initiated connects), clear the state so a subsequent drop
retries promptly. The 60s tokio::time::interval is kept as the wakeup,
gated per-peer by next_retry_at, since lightningdevkit#588's inline-sleep form does not
generalize to N peers. Backoff state is in-memory and resets on restart —
a fresh post-restart attempt is the correct behavior. State is also
cleared when a peer is removed from the persisted store.
Closeslightningdevkit#918.
Jolah1 added a commit to Jolah1/ldk-node that referenced this pull request Jul 10, 2026
Previously, the background reconnection task retried every persisted peer
on a fixed 60s interval with no backoff, so an unreachable peer was retried
indefinitely at the same cadence — log spam and wasted work. This became
more visible after lightningdevkit#895 retained peers across force-closes so that
channel_reestablish recovery can run.
Track per-peer reconnect state in ConnectionManager: on failure, double the
retry interval up to PEER_RECONNECTION_MAX_INTERVAL (30 min); on success
(including user-initiated connects), clear the state so a subsequent drop
retries promptly. The 60s tokio::time::interval is kept as the wakeup,
gated per-peer by next_retry_at, since lightningdevkit#588's inline-sleep form does not
generalize to N peers. Backoff state is in-memory and resets on restart —
a fresh post-restart attempt is the correct behavior. State is also
cleared when a peer is removed from the persisted store.
Closeslightningdevkit#918.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@tosynthegeek@ldk-reviews-bot@tnull