With the removal of Handle, there is no equivalent to Handle::current. For example, the following is no longer easily possible:
let handle = Handle::current();
std::thread::spawn(move || {
handle.block_on(...);
});
Is there more context on how this was used? The intended replacement was the user creating an Arc<Runtime>.
The main thing that Arc<Runtime> can't is to obtain a handle to the current runtime while being deep inside it.
Also, when using the tokio macro #[tokio::main] there is no way of accesssing the Arc<Runtime> unless I missed something?
Went through all of our use cases of Handle::current() and was able to refactor away all but 1 by using Arc<Runtime> instead. The last one is likely possible also but does require either passing a runtime very deep down the our stack, or storing it in a global which we really want to avoid.
But think we are pretty fine now without this functionality, and generally prefer an explicit Arc<Runtime> in the places that need it instead of it being magically available from anywhere with a Handle::current(). Will investigate some more though on our side
Also, when using the tokio macro #[tokio::main] there is no way of accesssing the Arc
unless I missed something?
This is indeed something I'm a bit concerned about, same with the test macros. We currently don't have use cases where we need to pass over the runtime to a separate thread inside a test but could see us having that. Can always simply not use the macro though and explicitly create the runtime, which we would be ok with but gets a bit messier for lots of tests.
But maybe the macro can provide a runtime accessor for inside the function?
In my case I was able to update my own code (by passing the runtime around to wherever I needed it), but when testing the application it panicked because some dependencies still tried to get a handle to the current runtime.
I understand that this could be considered a bug in the dependency (it should not panic) and that I should probably wait until de dependencies are updated to 0.3 as well, but I wondered what it will do to their APIs if they now need to specifically get the runtime passed down from the caller.
While its definitely possible to make things work, I personally think that being able to get a handle to the current runtime is a useful feature which in certain cases prevents having to pass the runtime throughout your entire codebase because of some leave branch might need to be able to access it.
You are using a tokio 0.3 runtime and your dependency is trying to get a handle to a tokio 0.2 runtime which is different from your tokio 0.3 runtime.
You can use the compat crate to spawn your code inside of a tokio 0.2 runtime which will leave alongside your tokio 0.3 one.
I think concern is following: if some library wants to have a &Runtime or an Arc<Runtime>, user has to manually pass it from main down to this library usage.
I think we can bring back a Handle type.
What about
```rust
impl Clone for Runtime {...}
impl Runtime {
pub fn try_current() -> Option
pub fn current() -> Self;
}
```
Hey @carllerche, any idea on a timeline for that? This is kind of a blocker right now for Rusty Celery (https://github.com/rusty-celery/rusty-celery/pull/195).
See #3076.
Reopening until a Handle::block_on is added to Handle. See #3096 for details.
It seems like there might be some bumps on the way to getting uniform access to the Runtime since Handle::current().block_on is stalled in #3097. Given that, I wanted to try and clarify what would be useful for our usecase, since not having uniform access is currently blocking our upgrade to 0.3.x.
In 0.2.x, Handle represented a uniform way to get access "to a Runtime" (not literally, but close enough: more on that below), regardless of whether it was created manually, or created in code we don't control and then fetched from the task-local via Handle::current. The latter case can occur for multiple reasons: 1) you're using tokio::test/tokio::main, which don't give you access to the Runtime instance, 2) you're a library that wants to avoid threading Runtime references throughout all of your APIs.
This issue indicates that we need a "Replacement for Handle::current", and so far the approach has been to resurrect Handle::current as it previously existed. But the most natural (external) API for uniform access to a Runtime would be to make the Runtime itself internally reference counted, have a Runtime::current method (via a task-local?), and do away with Handle. I expect that there were other reasons for the split (a Handle referencing "less than the entire Runtime", perhaps?)
For our particular usecase, versions of tokio::test/tokio::main that exposed an Arc<Runtime> to the annotated method would probably suffice as a replacement for Handle. But library users who do not have a reference to the runtime type threaded throughout their code would need to resort to other shenanigans (see @sunjay's comment on https://github.com/tokio-rs/tokio/pull/3097#issuecomment-744746083 for example).
But the most natural (external) API for uniform access to a
Runtimewould be to make theRuntimeitself internally reference counted, have aRuntime::currentmethod (via a task-local?), and do away withHandle.
This sounds like a great solution to me. (And it's definitely something to be decided on before 1.0 since removing Handle would be a breaking change.)
When I first saw that Handle was gone, I immediately reached for Runtime::current() and was disappointed to see that it didn't exist. This seems like a solution that would add no additional overhead to anyone who wasn't already cloning Runtime and it solves the problems many of us have had in upgrading to 0.3.
Actually I think there are some problems with making Runtime reference counted (or equivalently using Arc<Runtime>), because if the ref-counted runtime is stored in any future inside the runtime, then that is a reference-cycle and the runtime is keeping itself alive.
Additionally, if a task is holding on to the last reference of a runtime, that can cause problems when the task drops it, because that runs the destructor of the runtime inside the runtime, which may trigger panics regarding dropping runtimes inside runtimes because that is a blocking operation. Even if doesn't panic, it would deadlock because the destructor is waiting for the thread running the destructor to exit.
I prefer to find a solution to Handle::block_on because Handle is a _weak_ reference count, and as such neither problem applies.
Actually I think there are some problems with making
Runtimereference counted (or equivalently usingArc<Runtime>), because if the ref-counted runtime is stored in any future inside the runtime, then that is a reference-cycle and the runtime is keeping itself alive.
That makes sense, thanks!
I prefer to find a solution to
Handle::block_onbecauseHandleis a weak reference count, and as such neither problem applies.
Yea, reasonable. But it's only Handle::current that is fallible/a-weak-lookup, right? Or can Handle::spawn and Handle::spawn_blocking also fail because the Runtime has been-collected/gone-away?
Perhaps an alternative formulation would be to have an OwnedRuntime (strawname) that controls the lifetime of the Runtime, and to then have the existing Runtime type become equivalent to a weak reference? Or perhaps that's just a renaming of the existing concepts.
Or can
Handle::spawnandHandle::spawn_blockingalso fail because theRuntimehas been-collected/gone-away?
Yes. If you spawn on a dropped runtime through a Handle to that runtime, the returned JoinHandle will immediately fail with a JoinError saying that it has been cancelled.
The main problem with block_on is: What should happen if you block_on on a Handle to a runtime that doesn't exist anymore? Or worse, what if the runtime goes away while you are inside block_on? I don't know what Tokio 0.2 did, but the right answer is not obvious.
Perhaps an alternative formulation would be to have an
OwnedRuntime(strawname) that controls the lifetime of theRuntime, and to then have the existingRuntimetype become equivalent to a weak reference? Or perhaps that's just a renaming of the existing concepts.
Yes, this is just renaming. You turned Runtime into OwnedRuntime and Handle into Runtime.
Most helpful comment
Also, when using the tokio macro
#[tokio::main]there is no way of accesssing theArc<Runtime>unless I missed something?