-
Notifications
You must be signed in to change notification settings - Fork 2.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Replace task run()
return result with custom enum
#2429
base: master
Are you sure you want to change the base?
Conversation
@@ -137,8 +138,7 @@ impl RunnableService for SyncTask { | |||
|
|||
#[async_trait::async_trait] | |||
impl RunnableTask for SyncTask { | |||
#[tracing::instrument(level = "debug", skip_all, err, ret)] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Had to remove this from a couple locations since the instrument
macro assumes the function returns Result
@@ -196,11 +197,15 @@ impl RunnableService for GraphqlService { | |||
|
|||
#[async_trait::async_trait] | |||
impl RunnableTask for Task { | |||
async fn run(&mut self, _: &mut StateWatcher) -> anyhow::Result<bool> { | |||
self.server.as_mut().await?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change introduces a non-trivial amount of noise with the removal of the ?
operators.
AFAICT, there isn't a way to implement Try
for arbitrary types in Rust which is a real bummer.
} | ||
} | ||
} | ||
should_continue = true; | ||
} | ||
} | ||
|
||
Ok(should_continue) | ||
TaskRunResult::should_continue(should_continue) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I though the idea was to remove should_continue
variable and replace with the usage of the enum=D
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My goal was to change the interface.
I'm happy to do some more refactoring too.
let da_block_costs = self.source.request_da_block_cost().await?; | ||
self.shared_state.0.send(da_block_costs)?; | ||
continue_running = true; | ||
match self.source.request_da_block_cost().await.and_then(|da_block_costs| self.shared_state.0.send(da_block_costs).map_err(|err| anyhow::anyhow!(err))) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is very hard to read, maybe we could it inside of the function and process the result of the function?=)
let block = match l2_block_res { | ||
Ok(block) => block, | ||
Err(err) => { | ||
return anyhow!(err).into() | ||
} | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see this pattern in many places. Maybe it would be simpler to defined a helper trait with into_continue_task_result
which either returns TaskRunResult::Continue
or TaskRunResult::ErrorContinue
tracing::debug!("stopping"); | ||
break; | ||
} | ||
TaskRunResult::ErrorContinue(e) => { | ||
let e: &dyn std::error::Error = &*e; | ||
tracing::error!(e); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
would it make sense to add a debug! statement to explicitly tell that the loop will continue (similar to the Continue
case)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure I understand. Are you talking in the ErrorContinue
case? I feel like we should definitely use error!
there, especially since we don't exit on errors.
let res = self.process_da_block_costs_res(da_block_costs).await; | ||
TaskRunResult::Continue |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we have error here, you will not propagate it to the caller of the run
function and we will miss log for this error.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for catching this.
crates/services/p2p/src/service.rs
Outdated
@@ -916,7 +915,12 @@ where | |||
} | |||
Some(TaskRequest::RespondWithGossipsubMessageReport((message, acceptance))) => { | |||
// report_message(&mut self.p2p_service, message, acceptance); | |||
self.p2p_service.report_message(message, acceptance)?; | |||
match self.p2p_service.report_message(message, acceptance) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nit] if let Err(err) = res
fits better here.
crates/services/src/service.rs
Outdated
|
||
impl TaskRunResult { | ||
/// Creates a `TaskRunResult` from a `Result` where `Ok` means `Continue` and any error is reported | ||
pub fn continue_if_ok<T, E: Into<anyhow::Error>>(res: Result<T, E>) -> TaskRunResult { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
continue_if_ok
is a bad name. I thought it returns Continue
only If it is Ok
.
What do you think about always_continue
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought it returns Continue only If it is Ok.
Yeah. It returns continue_
only if_
it is ok
. I doesn't always_
return continue
... I'm confused why you want me to change it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It returns Continue
or ErrorContinue
, which continues the task even if an error occurred.
From the function with name continue_if_ok
I would expect return Continue
on Ok
and return Stop
on Err
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see now. That is confusing. I feel like "always continue" is confusing for the opposite reason though. "continue or error"? Haha
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe just continue
then?=) For me, the main point here is that we should still continue the task. What happens with error is not important for me as a reader of the code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah. I think you're right. I think that's what the caller is interested in. I'll go with one of those.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel like TaskRunResult is the wrong name then. It's almost a state machine but not quite. But TaskState or TaskStateTransition might be a better name...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I went with always_continue
and TaskNextAction
(I asked ChatGPT for a good name and that was the one I liked the most)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM 👍
with some nits/suggestions
Anyway, good piece of QoL code :)
@@ -568,16 +568,19 @@ where | |||
// de-synchronization between on-chain and off-chain databases. | |||
if let Err(e) = result { | |||
tracing::error!("Error processing block: {:?}", e); | |||
should_continue = self.continue_on_error; | |||
if self.continue_on_error { | |||
TaskNextAction::Continue |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why not ErrorContinue
here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah. Good idea. I was going to say that I want to maintain the old behavior, but that's essentially the same and cleaner.
9481e5c
Linked Issues/PRs
closes: #2441
Description
Before any
RunnableTask
would return aResult<bool>
where, implicitly, thebool
was telling the service runner if it should re-run the task.This is confusing from the customer perspective since you need to understand the behavior of
ServiceRunner
in order to choose the right response: i.e.Ok(true)
meant you want to rerun. Instead this PR adds theContinue
andStop
variants.It was also confusing with
Error
since, unintuitively, anError
would result in the task being run again. This PR adds theErrorContinue
variant, so the implementer know explicitly what the behavior is.Checklist
Before requesting review
After merging, notify other teams
[Add or remove entries as needed]