The application panicked (crashed).
Message: Cannot start a runtime from within a runtime. This happens because a function (like `block_on`) attempted to block the current thread while the thread is being used to drive asynchronous tasks.
Location: C:\Users\JR\.cargo\registry\src\github.com-1ecc6299db9ec823\tokio-0.2.22\src\runtime\enter.rs:38
More progress...
There seems to be some libraries that don't like the
tokio::runtime::Handle::current.block_on()...
And some that do...
reqwest works, trust-dns does not... which is weird, since reqwest uses trust-dns under the hood.
What do you mean with them not liking handle.block_on()? Perhaps verify that the versions are correct, i.e. that the library didn't expect Tokio 0.3. You can do this on docs.rs at the top of the page. Here you can open a drop-down by clicking the crate name in the toolbar, and the dropdown will have a list of dependencies including their version.
Well the problem is that if you call a sync function from async code without a spawn_blocking, then that function may not block. The mistake is in main where you called our_cave, or that our_cave is not an async fn.
Yes... That is the problem...
Imagine there is a 50+ stack frames between main and cave...
Quite frequently, when dealing with external libraries and systems, this is a necessary evil...
If I read your response correctly...
After calling one async function, it would be a mistake to call a sync function, that may or may not call an async function again...
That's not practical in the real world.
Without rewriting all impl, trait, and every crate out there to be async, we will all hit this bump at some point.
So, again philosophy aside...
What is the best / correct approach to dealing with it.
As an example...
reqwest has both a sync and async implementation...
The sync implementation relies on the async one under the hood.
and it may spawn a tokio runtime...
// reqwest/src/blocking/client.rs Client::execute_reqwest()
let f = async move {
body.send().await?;
rx.await.map_err(|_canceled| event_loop_panicked())
};
wait::timeout(f, timeout)
So, it is something people will have to do, and a generic solution would be optimal....
It is the reality. It is true that there are some crates this prevents you from using, but that's a consequence of how async/await works. It is not compatible with all other crates.
You can try to use block_in_place, but as I mentioned before, it's a footgun due to its extra non-local requirements.
There are no other possible solutions than what is offered by block_in_place. It is simply theoretically impossible to fix it in any other way besides completely changing how async/await is implemented.
OK, I understand...
I all systems, there are compromises...
I love the language and the libraries... So, these are just issues we'll have to find a way around...
Even though we'll have to use the sledge-hammer and fancy-footwork at times..
Perhaps someone will come up with a good generic solution and publish it in a crate...
I like @seanmonstar solution in reqwest, a wait with a timeout...
Too bad it is "pub(crate)"...
Again, I really appreciate the assistance and insight...
JR
The timeout in reqwest is for when people actually want a timeout on their http requests, not as a workaround for people calling the blocking version in async code.
As for your sledge-hammer, that is block_in_place.
It is indeed....
There is little difference in my mind between the http timeout and a timeout for a runaway thread.
The goal is to prevent one sub-system / thread from monopolizing the resources.
A timeout is gold if a subsystem is stuck in a poll with a runaway process...
At least the effects are limited..
Philosophically...
All sledge-hammers should have an option of a timeout.
I've made a tiny crate, spin_on, that implements this very simple executor. I added a spin_loop_hint inside the spin loop that might help with performance on systems that support it.