-
Notifications
You must be signed in to change notification settings - Fork 12
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
perf: run historical and realtime sync in parallel + refactor indexer…
…'s and synchronizer's error logging
- Loading branch information
Showing
9 changed files
with
253 additions
and
155 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
use crate::{clients::common::ClientError, synchronizer::error::SynchronizerError}; | ||
|
||
#[derive(Debug, thiserror::Error)] | ||
pub enum IndexerError { | ||
#[error(transparent)] | ||
ClientError(#[from] ClientError), | ||
#[error(transparent)] | ||
Other(#[from] anyhow::Error), | ||
#[error(transparent)] | ||
ReqwestEventSourceError(#[from] reqwest_eventsource::Error), | ||
#[error("{0}")] | ||
SerdeError(#[from] serde_json::Error), | ||
#[error(transparent)] | ||
SynchronizerError(#[from] SynchronizerError), | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,187 @@ | ||
use futures::StreamExt; | ||
use reqwest_eventsource::Event; | ||
use tokio::{sync::mpsc, task::JoinHandle}; | ||
use tracing::{debug, error}; | ||
|
||
use crate::{ | ||
args::Args, | ||
clients::{ | ||
beacon::types::{BlockId, HeadBlockEventData, Topic}, | ||
blobscan::types::BlockchainSyncState, | ||
}, | ||
context::{Config as ContextConfig, Context}, | ||
env::Environment, | ||
synchronizer::{Synchronizer, SynchronizerBuilder}, | ||
}; | ||
|
||
use self::{error::IndexerError, types::IndexerResult}; | ||
|
||
pub mod error; | ||
pub mod types; | ||
|
||
pub struct Indexer { | ||
context: Context, | ||
num_threads: Option<u32>, | ||
slots_checkpoint: Option<u32>, | ||
} | ||
|
||
impl Indexer { | ||
pub fn try_new(env: &Environment, args: &Args) -> IndexerResult<Self> { | ||
let context = match Context::try_new(ContextConfig::from(env)) { | ||
Ok(c) => c, | ||
Err(error) => { | ||
error!(target = "indexer", ?error, "Failed to create context"); | ||
|
||
return Err(error.into()); | ||
} | ||
}; | ||
|
||
Ok(Self { | ||
context, | ||
num_threads: args.num_threads, | ||
slots_checkpoint: args.slots_per_save, | ||
}) | ||
} | ||
|
||
pub async fn run(&mut self, start_block_id: Option<BlockId>) -> IndexerResult<()> { | ||
Check failure on line 46 in src/indexer/mod.rs
|
||
let sync_state = match self.context.blobscan_client().get_sync_state().await { | ||
Ok(state) => state, | ||
Err(error) => { | ||
error!(target = "indexer", ?error, "Failed to fetch sync state"); | ||
|
||
return Err(error.into()); | ||
} | ||
}; | ||
|
||
let current_lower_block_id = match &sync_state { | ||
Some(state) => match state.last_lower_synced_slot { | ||
Some(slot) => BlockId::Slot(slot - 1), | ||
None => BlockId::Head, | ||
}, | ||
None => BlockId::Head, | ||
}; | ||
let current_upper_block_id = match &sync_state { | ||
Some(state) => match state.last_upper_synced_slot { | ||
Some(slot) => BlockId::Slot(slot + 1), | ||
None => BlockId::Head, | ||
}, | ||
None => BlockId::Head, | ||
}; | ||
|
||
let (tx, mut rx) = mpsc::channel(32); | ||
let tx1 = tx.clone(); | ||
|
||
self._start_historical_sync_task(tx1, current_lower_block_id)?; | ||
self._start_realtime_sync_task(tx, current_upper_block_id)?; | ||
|
||
while let Some(message) = rx.recv().await { | ||
if let Err(error) = message { | ||
return Err(error.into()); | ||
Check failure on line 79 in src/indexer/mod.rs
|
||
} | ||
} | ||
|
||
Ok(()) | ||
} | ||
|
||
fn _start_historical_sync_task( | ||
&self, | ||
tx: mpsc::Sender<IndexerResult<()>>, | ||
start_block_id: BlockId, | ||
) -> IndexerResult<JoinHandle<()>> { | ||
let mut synchronizer = self._create_synchronizer()?; | ||
|
||
let handler = tokio::spawn(async move { | ||
let result = synchronizer.run(&start_block_id, &BlockId::Slot(0)).await; | ||
|
||
if let Err(error) = result { | ||
// TODO: Find a better way to handle this error | ||
tx.send(Err(error.into())).await.unwrap(); | ||
}; | ||
}); | ||
|
||
Ok(handler) | ||
} | ||
|
||
fn _start_realtime_sync_task( | ||
&self, | ||
tx: mpsc::Sender<IndexerResult<()>>, | ||
start_block_id: BlockId, | ||
) -> IndexerResult<JoinHandle<IndexerResult<()>>> { | ||
let task_context = self.context.clone(); | ||
let mut synchronizer = self._create_synchronizer()?; | ||
|
||
let handler = tokio::spawn(async move { | ||
let result = async { | ||
let blobscan_client = task_context.blobscan_client(); | ||
let mut event_source = task_context | ||
.beacon_client() | ||
.subscribe_to_events(vec![Topic::Head])?; | ||
let mut current_block_id = start_block_id; | ||
|
||
while let Some(event) = event_source.next().await { | ||
match event { | ||
Ok(Event::Open) => { | ||
debug!(target = "indexer", "Listening for head block events…") | ||
} | ||
Ok(Event::Message(event)) => { | ||
let head_block_data = | ||
serde_json::from_str::<HeadBlockEventData>(&event.data)?; | ||
let head_block_id = BlockId::Slot(head_block_data.slot); | ||
|
||
synchronizer | ||
.run(¤t_block_id, &head_block_id) | ||
.await | ||
.map_err(|err| IndexerError::SynchronizerError(err.into()))?; | ||
Check failure on line 134 in src/indexer/mod.rs
|
||
|
||
blobscan_client | ||
.update_sync_state(BlockchainSyncState { | ||
last_lower_synced_slot: None, | ||
last_upper_synced_slot: Some(head_block_data.slot), | ||
}) | ||
.await?; | ||
|
||
current_block_id = head_block_id; | ||
} | ||
Err(error) => { | ||
event_source.close(); | ||
|
||
error!( | ||
target = "indexer", | ||
?error, | ||
"Failed to received head block event" | ||
); | ||
|
||
return Err(error.into()); | ||
} | ||
} | ||
} | ||
|
||
Ok(()) | ||
} | ||
.await; | ||
|
||
if let Err(error) = result { | ||
// TODO: Find a better way to handle this error | ||
tx.send(Err(error)).await.unwrap(); | ||
}; | ||
|
||
Ok(()) | ||
}); | ||
|
||
Ok(handler) | ||
} | ||
|
||
fn _create_synchronizer(&self) -> IndexerResult<Synchronizer> { | ||
let mut synchronizer_builder = SynchronizerBuilder::new()?; | ||
|
||
if let Some(num_threads) = self.num_threads { | ||
synchronizer_builder.with_num_threads(num_threads); | ||
} | ||
|
||
if let Some(slots_checkpoint) = self.slots_checkpoint { | ||
synchronizer_builder.with_slots_checkpoint(slots_checkpoint); | ||
} | ||
|
||
Ok(synchronizer_builder.build(self.context.clone())) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
use super::error::IndexerError; | ||
|
||
pub type IndexerResult<T> = Result<T, IndexerError>; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.