-
-
Notifications
You must be signed in to change notification settings - Fork 2.5k
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
Consider making JoinHandle cancel on drop #1830
Comments
As an alternative, we could add a I'm not sure if this is a better approach to the proposed change, but it's worth considering. It's worth noting that since it's not a breaking change, we could get an opt-in task cancellation change in before 0.3. That way, users can start trying it out sooner, and if it proves to be the right thing, we could make it the default in 0.3. Personal opinions to follow: IMO, opting in to "leaking" rather than opting out is a better design in isolation. However, it's strange to have an API that's almost exactly identical to
My vote is for |
Cancel on drop would greatly simplify cancellation of dependent tasks and effectively obsolete hoops like On top of that, I would support making it the default behaviour. While it is not really feasible to cancel the running thread, tasks are not subject to this limitation. Therefore we have an option of aligning this part of API with idiomatic Rust by defaulting to managing said task via a handle just like any other resource. It should have higher priority than blindly mimicking std. |
I feel like the entire idea of If would much prefer it the other way around. Add a
Also as @carllerche just wrote in the Discord chat: It would be very confusing if the following code would become a noop because the handle is dropped immediately.
|
FWIW, I think this issue in particular could be solved just by putting a |
@hawkw it doesn't, because during early dev, it's usual to have a wall of warnings while "getting something working"... the warning will be lost. |
I also think that "cancel on drop" is only a partial solution. A cancel on drop will be a forceful cancellation which will prevent the task from being able to do cleanup. ATM, I am much more keen on a holistic approach to solving the problem: #1879 |
Sure, but if the spawned task is immediately cancelled, then the code won't work, and the warning would make it much clearer why it doesn't work. I think if we have a |
I find it unfortunate to solve these issues at the framework level. The need for a JoinHandle type that can "detach", "drop" and return a value is there for all async rust code, and it would allow libraries to use it without locking their clients into a specific framework. For now the futures library has
What if the futures library would have a satisfying
I might have to think and experiment a bit more, but I think (forcibly) cancellable tasks are a fundamental building block to making structured concurrency happen. Since you're going to join every task, you can't afford a random task blocking the whole application. |
It turns out I was mistaking about Which makes me wonder, what is the motivation for not using it but rolling a custom |
|
Just wondering, is it possible to cancel tasks right now with the current api? If not what's the "best" current workaround for cancelling tasks? |
@cynecx you can use |
You can also just select the task against a oneshot for example. I think making joinhandle cancel on drop can be surprising. |
Wouldn't cancel-on-drop make it easier to implement |
@peku33 yes, a currently running poll will complete before the future can be aborted. But that being said, how would you stop a sequence of instructions running in the cpu if that sequence provides no means of being interrupted? |
@peku33 ultimately cancel-on-drop does not help with non-static futures because of |
We discussed this in slack and decided not to move forward with this. There was no consensus either way, but most were either not strong advocates, on the fence, or against. There also is not enough time to experiment with this before 1.0. Not canceling on drop matches std behavior around It is also worth noting that a forceful cancellation is almost never the correct behavior. One needs to perform a graceful cancellation where a shutdown signal is sent followed by joining on the handle. The primary argument for cancel on drop is that it is "easier" to catch a no-op bug than leaking tasks. Tokio provides the necessary infrastructure to implement this behavior externally. This can be done by wrapping the |
@carllerche - But this structure doesn't have an "abort" method. |
@szagi3891 It was added by #2474, which was merged 14 days ago. |
Thank you for the information, I'll be happy to use it :) When is the new version of "tokyo" coming out? And is it possible to read the number of "tasks"? This could be useful for checking that a task is not leaking. |
Task spawning is instrumented w/ |
The unfortunate part about all this, I think, is that once you give your, say, 2 join handles to Practical problem where this can arise is arguably fairly common - e.g. you want to have an HTTP endpoint and a GRPC endpoint in your program, or, say, HTTP REST and Prometheus instrumentation, or whatever - the key thing is two separate task must run until one of them fails, and be aborted if that happens, so the program could exit. That said, I'm very much a beginner in Rust, so maybe I'm just "holding it wrong". |
Well yes, it's a tradeoff. When it comes to |
Is there any crate implementing the drop wrapper? |
async_executors homogenizes the API across async frameworks and has a |
Thanks. |
In Tokio 0.2,
tokio::task::spawn
now returns aJoinHandle
which is aFuture
of when the task completes. It currently behaves the same asstd::thread::JoinHandle
, which will "detach" it automatically if ignored.I want to propose that we change this behavior such that dropping a
JoinHandle
cancels the associated task.Motivation
std::thread::JoinHandle
doesn't cancel the associated thread when dropped is because there's no real way to cancel an OS thread.Task
.oneshot
or similar. It can also be surprising that even if a user did try to hold onto theJoinHandle
to prevent a leak, if the wrapping future is dropped, the spawned task will still "leak".Change
JoinHandle::daemonize()
(ordetach
orbackground
) so that "leaking" some task is an explicit action.The text was updated successfully, but these errors were encountered: