Skip to content

[Chain Orchestrator] Retry on failure #319

@frisitano

Description

@frisitano

Overview

If we have a failure when processing a future in the chain orchestrator and the error is associated with some transient error, such as DatabaseError, NetworkRequestError or RpcError, then we should retry the future until completion. This prevents transient errors from impacting the chain orchestrator. We can do this by marking the error types as retryable or not e.g.

impl ChainOrchestratorError {
    fn can_retry(&self) -> bool {
        matches!(
            self,
            ChainOrchestratorError::DatabaseError(_) |
                ChainOrchestratorError::NetworkRequestError(_) |
                ChainOrchestratorError::RpcError(_)
        )
    }
}

We would then implement the retry logic in the Stream implementation of the ChainOrchestrator:

impl<
ChainSpec: ScrollHardforks + 'static,
BC: BlockClient<Block = ScrollBlock> + Send + Sync + 'static,
P: Provider<Scroll> + Send + Sync + 'static,
> Stream for ChainOrchestrator<ChainSpec, BC, P>
{
type Item = Result<ChainOrchestratorEvent, ChainOrchestratorError>;
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
// Register the waker such that we can wake when required.
self.waker.register(cx.waker());
// Remove and poll the next future in the queue
while let Some(mut action) = self.pending_futures.pop_front() {
match action.poll(cx) {
Poll::Ready(result) => match result {
Ok(None) => {}
Ok(Some(event)) => return Poll::Ready(Some(Ok(event))),
Err(e) => return Poll::Ready(Some(Err(e))),
},
Poll::Pending => {
self.pending_futures.push_front(action);
return Poll::Pending
}
};
}
Poll::Pending
}
}

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions