Skip to content

Commit 667fc82

Browse files
committed
relay: retry EVM chain id query with backoff at startup
The startup path queried evm_client.get_chain_id() once and bailed on failure; a brief RPC outage at boot would kill the relayer. Bounded exponential backoff (1s, 2s, 4s, 8s, 16s — ~31s total) lets a flaky RPC recover before we give up while still surfacing a hard outage as a clean startup error.
1 parent 203ff9f commit 667fc82

1 file changed

Lines changed: 31 additions & 4 deletions

File tree

linera-bridge/src/relay/mod.rs

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,36 @@ pub(crate) async fn update_balance_metrics<
5454
update_linera_balance_metric(linera_client).await;
5555
}
5656

57+
/// Polls the EVM RPC for the chain id with bounded exponential backoff
58+
/// so a brief RPC outage at startup does not kill the relayer. Backs
59+
/// off 1s, 2s, 4s, 8s, 16s; gives up after ~31s with the underlying
60+
/// error so the operator still sees a clean failure on a hard outage.
61+
async fn fetch_evm_chain_id_with_retry<P: alloy::providers::Provider>(
62+
evm_client: &evm::EvmClient<P>,
63+
) -> Result<u64> {
64+
let mut delay = Duration::from_secs(1);
65+
let max_delay = Duration::from_secs(16);
66+
let mut last_error: Option<anyhow::Error> = None;
67+
for attempt in 1..=5 {
68+
match evm_client.get_chain_id().await {
69+
Ok(id) => return Ok(id),
70+
Err(error) => {
71+
tracing::warn!(
72+
attempt,
73+
?delay,
74+
?error,
75+
"EVM chain id query failed; retrying after backoff"
76+
);
77+
last_error = Some(error);
78+
tokio::time::sleep(delay).await;
79+
delay = (delay * 2).min(max_delay);
80+
}
81+
}
82+
}
83+
Err(last_error.unwrap_or_else(|| anyhow::anyhow!("EVM chain id query failed")))
84+
.context("failed to query EVM chain id for monitor state after retries")
85+
}
86+
5787
pub(crate) async fn update_evm_balance_metric<P: alloy::providers::Provider>(
5888
evm_client: &evm::EvmClient<P>,
5989
) {
@@ -317,10 +347,7 @@ async fn serve_loop<E: linera_core::environment::Environment + 'static>(
317347
let mut chain_listener_handle = tokio::spawn(listener);
318348

319349
// ── Monitor state + scan/retry ──
320-
let source_chain_id = evm_client
321-
.get_chain_id()
322-
.await
323-
.context("failed to query EVM chain id for monitor state")?;
350+
let source_chain_id = fetch_evm_chain_id_with_retry(&evm_client).await?;
324351
let mut monitor_state = MonitorState::new(monitor_start_block, source_chain_id);
325352
let default_sqlite_path = storage_dir
326353
.parent()

0 commit comments

Comments
 (0)