|
| 1 | +//! Robust, retrying wrapper around Alloy providers. |
| 2 | +//! |
| 3 | +//! This module exposes [`RobustProvider`], a small wrapper around Alloy's |
| 4 | +//! `RootProvider` that adds: |
| 5 | +//! * bounded per-call timeouts |
| 6 | +//! * exponential backoff retries |
| 7 | +//! * transparent failover between a primary and one or more fallback providers |
| 8 | +//! * more robust WebSocket block subscriptions with automatic reconnection |
| 9 | +//! |
| 10 | +//! Use [`RobustProviderBuilder`] to construct a provider with sensible defaults |
| 11 | +//! and optional fallbacks, or implement the [`IntoRobustProvider`] and [`IntoProvider`] |
| 12 | +//! traits to support custom providers. |
| 13 | +//! |
| 14 | +//! # How it works |
| 15 | +//! |
| 16 | +//! All RPC calls performed through [`RobustProvider`] are wrapped in a total |
| 17 | +//! timeout and retried with exponential backoff up to `max_retries`. If the |
| 18 | +//! primary provider keeps failing, the call is retried against the configured |
| 19 | +//! fallback providers in the order they were added. For subscriptions, |
| 20 | +//! [`RobustSubscription`] also tracks lag, switches to fallbacks on repeated |
| 21 | +//! failure, and periodically attempts to reconnect to the primary provider. |
| 22 | +//! |
| 23 | +//! # Examples |
| 24 | +//! |
| 25 | +//! Creating a robust WebSocket provider with a fallback: |
| 26 | +//! |
| 27 | +//! ```rust,no_run |
| 28 | +//! use alloy::providers::{Provider, ProviderBuilder}; |
| 29 | +//! use event_scanner::robust_provider::RobustProviderBuilder; |
| 30 | +//! use std::time::Duration; |
| 31 | +//! use tokio_stream::StreamExt; |
| 32 | +//! |
| 33 | +//! # async fn example() -> anyhow::Result<()> { |
| 34 | +//! let ws = ProviderBuilder::new().connect("ws://localhost:8545").await?; |
| 35 | +//! let ws_fallback = ProviderBuilder::new().connect("ws://localhost:8456").await?; |
| 36 | +//! |
| 37 | +//! let robust = RobustProviderBuilder::new(ws) |
| 38 | +//! .fallback(ws_fallback) |
| 39 | +//! .call_timeout(Duration::from_secs(30)) |
| 40 | +//! .subscription_timeout(Duration::from_secs(120)) |
| 41 | +//! .build() |
| 42 | +//! .await?; |
| 43 | +//! |
| 44 | +//! // Make RPC calls with automatic retries and fallback |
| 45 | +//! let block_number = robust.get_block_number().await?; |
| 46 | +//! println!("Current block: {}", block_number); |
| 47 | +//! |
| 48 | +//! // Create subscriptions that automatically reconnect on failure |
| 49 | +//! let sub = robust.subscribe_blocks().await?; |
| 50 | +//! let mut stream = sub.into_stream(); |
| 51 | +//! while let Some(response) = stream.next().await { |
| 52 | +//! match response { |
| 53 | +//! Ok(block) => println!("New block: {:?}", block), |
| 54 | +//! Err(e) => println!("Got error: {:?}", e), |
| 55 | +//! } |
| 56 | +//! } |
| 57 | +//! # Ok(()) } |
| 58 | +//! ``` |
| 59 | +//! |
| 60 | +//! You can also convert existing providers using [`IntoRobustProvider`] |
| 61 | +
|
1 | 62 | pub mod builder; |
2 | 63 | pub mod error; |
3 | 64 | pub mod provider; |
|
0 commit comments