-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Implement Future for SpawnedTask. #15653
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
Conversation
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.
Thanks @ashdnazg for this contribution.
Implementing future for spawned task seems fine to me but I am not sure about changing to use a join handle (even though implemeting Drop to call abort might be fine)
Can you please add tests showing that any tasks launched by spawned tasks are actually cancelled (both before and after they have started)?
@alamb I added two tests for the two scenarios. |
use crate::JoinSet; | ||
use tokio::task::JoinError; | ||
use tokio::task::{JoinError, JoinHandle}; |
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 think not using crate::JoinSet
is going to render the work being done by @geoffreyclaude in #14547 pretty much useless. Is this right @geoffreyclaude?
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 we can just add something similar to the spawned task
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.
Good catch @gabotechs! Yes, pretty much. For both to be compatible, the same wrapping I implemented over the tokio::task::JoinSet
probably needs to be done over tokio::task::spawn
and tokio::task::spawn_blocking
.
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.
@ashdnazg I'll try to add unit tests for the instrumentation feature tomorrow which you could use to validate your change doesn't introduce any regression.
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.
@geoffreyclaude I updated the PR with the tracing functions wrapping the spawned tasks.
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.
Tests should be more reliable now 🤦. |
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 looks really nice to me -- thank you @ashdnazg 🙏
Let's wait a while before merging to give @geoffreyclaude and others a chance to review it again if they want.
I went through this one carefully and I think it is 👨🍳 👌 very nice.
let mut inner = JoinSet::new(); | ||
inner.spawn(task); | ||
#[allow(clippy::disallowed_methods)] | ||
let inner = tokio::task::spawn(trace_future(task)); |
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 think some rationale about why it is ok to use the disallowed methods would help. Something like:
let inner = tokio::task::spawn(trace_future(task)); | |
// Ok to use spawn here as SpawnedTask handles aborting/cancelling the task on Drop | |
let inner = tokio::task::spawn(trace_future(task)); |
@@ -47,22 +54,20 @@ impl<R: 'static> SpawnedTask<R> { | |||
T: Send + 'static, | |||
R: Send, | |||
{ | |||
let mut inner = JoinSet::new(); | |||
inner.spawn_blocking(task); | |||
#[allow(clippy::disallowed_methods)] |
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.
#[allow(clippy::disallowed_methods)] | |
// Ok to use spawn here as SpawnedTask handles aborting/cancelling the task on Drop | |
#[allow(clippy::disallowed_methods)] |
|
||
#[tokio::test] | ||
async fn runtime_shutdown() { | ||
let rt = Runtime::new().unwrap(); | ||
#[allow(clippy::async_yields_async)] |
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 think this is ok -- the only reason clippy picks this up now is that SpawnedTask
is actually a future where previously one had to call join().await
-- so TLDR this change makes sense to me (though the test is perhaps somewhat suspect)
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 you want, I can change the rt.spawn
to rt.spawn_blocking
and then we get rid of both the unnecessary surrounding async
and the clippy thing.
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 we can add a second test -- I think we should leave the existing test as is as part of ensuring this PR doesn't introduce any regressiosn
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.
A second test wouldn't test anything new IMO so keeping as is.
Thanks! Looks good to me, especially if the new tests pass. @ashdnazg could you please just rebase on top of main so the CI picks up my merged tests? |
It allows polling a SpawnedTask, instead of just joining it. The implementation is changed from `JoinSet` to a `JoinHandle` to simplify the code, as `JoinSet` doesn't provide any additional benefits.
496140a
to
b47dbba
Compare
Rebased and added docs per @alamb 's suggestions. |
all the tests are green so let's go go go! |
@ashdnazg thank you for your contribution, hope to see you contribute again! |
It allows polling a SpawnedTask, instead of just joining it. The implementation is changed from `JoinSet` to a `JoinHandle` to simplify the code, as `JoinSet` doesn't provide any additional benefits.
Rationale for this change
Allows polling a
SpawnedTask
, instead of just joining it.Required for #15654
What changes are included in this PR?
An
impl Future
was added toSpawnedTask
.In addition, the underlying implementation is changed from
JoinSet
to aJoinHandle
to simplifythe code, as
JoinSet
doesn't provide any additional benefits.Documentation was also updated to make clearer what happens when
spawn_blocking
is called.Are these changes tested?
Added two tests that verify the behaviour on
spawn
.Are there any user-facing changes?
No, although
SpawnedTask
is public so it does add to the API.