Tokio Recursion Error

@alice

Thank you !!
It helped me !!

But why there was a recursion with tokio::spawn(handle_url(url)); ???

@alice
It helps, but another error occur at runtime !!

Url path is https://docs.rs/tokio/0.2.19/tokio/signal/index.html
thread 'tokio-runtime-worker' panicked at 'gai background task failed: JoinError::Cancelled', {MyPath}\.cargo\registry\src\github.com-1ecc6299db9ec823\hyper-0.13.5\src\client\connect\dns.rs:144:30
stack backtrace:
   0: backtrace::backtrace::trace_unsynchronized
             at C:\Users\VssAdministrator\.cargo\registry\src\github.com-1ecc6299db9ec823\backtrace-0.3.46\src\backtrace\mod.rs:66
   1: std::sys_common::backtrace::_print_fmt
             at /rustc/edc02580e4e80476ac1ded2cc1008eaf8b8400e6\/src\libstd\sys_common\backtrace.rs:78
   2: std::sys_common::backtrace::_print::{{impl}}::fmt
             at /rustc/edc02580e4e80476ac1ded2cc1008eaf8b8400e6\/src\libstd\sys_common\backtrace.rs:59
   3: core::fmt::write
             at /rustc/edc02580e4e80476ac1ded2cc1008eaf8b8400e6\/src\libcore\fmt\mod.rs:1069
   4: std::io::Write::write_fmt<std::sys::windows::stdio::Stderr>
             at /rustc/edc02580e4e80476ac1ded2cc1008eaf8b8400e6\/src\libstd\io\mod.rs:1504
   5: std::sys_common::backtrace::_print
             at /rustc/edc02580e4e80476ac1ded2cc1008eaf8b8400e6\/src\libstd\sys_common\backtrace.rs:62
   6: std::sys_common::backtrace::print
             at /rustc/edc02580e4e80476ac1ded2cc1008eaf8b8400e6\/src\libstd\sys_common\backtrace.rs:49
   7: std::panicking::default_hook::{{closure}}
             at /rustc/edc02580e4e80476ac1ded2cc1008eaf8b8400e6\/src\libstd\panicking.rs:198
   8: std::panicking::default_hook
             at /rustc/edc02580e4e80476ac1ded2cc1008eaf8b8400e6\/src\libstd\panicking.rs:218
   9: std::panicking::rust_panic_with_hook
             at /rustc/edc02580e4e80476ac1ded2cc1008eaf8b8400e6\/src\libstd\panicking.rs:511
  10: std::panicking::begin_panic_handler
             at /rustc/edc02580e4e80476ac1ded2cc1008eaf8b8400e6\/src\libstd\panicking.rs:419
  11: std::panicking::begin_panic_fmt
             at /rustc/edc02580e4e80476ac1ded2cc1008eaf8b8400e6\/src\libstd\panicking.rs:373
  12: hyper::client::connect::dns::{{impl}}::poll::{{closure}}
             at {MyPath}\.cargo\registry\src\github.com-1ecc6299db9ec823\hyper-0.13.5\src\client\connect\dns.rs:144
  13: core::task::poll::Poll<core::result::Result<core::result::Result<hyper::client::connect::dns::IpAddrs, std::io::error::Error>, tokio::runtime::task::error::JoinError>>::map<core::result::Result<core::result::Result<hyper::client::connect::dns::IpAddrs, st
             at {MyPath}\.rustup\toolchains\nightly-x86_64-pc-windows-msvc\lib\rustlib\src\rust\src\libcore\task\poll.rs:33
  14: hyper::client::connect::dns::{{impl}}::poll
             at {MyPath}\.cargo\registry\src\github.com-1ecc6299db9ec823\hyper-0.13.5\src\client\connect\dns.rs:141
  15: core::future::poll_with_context<hyper::client::connect::dns::GaiFuture>
             at {MyPath}\.rustup\toolchains\nightly-x86_64-pc-windows-msvc\lib\rustlib\src\rust\src\libcore\future\mod.rs:84
  16: hyper::client::connect::dns::resolve::{{closure}}<hyper::client::connect::dns::GaiResolver>
             at {MyPath}\.cargo\registry\src\github.com-1ecc6299db9ec823\hyper-0.13.5\src\client\connect\dns.rs:342
  17: core::future::from_generator::{{impl}}::poll<generator-0>
             at {MyPath}\.rustup\toolchains\nightly-x86_64-pc-windows-msvc\lib\rustlib\src\rust\src\libcore\future\mod.rs:66
  18: core::future::poll_with_context<core::future::from_generator::GenFuture<generator-0>>
             at {MyPath}\.rustup\toolchains\nightly-x86_64-pc-windows-msvc\lib\rustlib\src\rust\src\libcore\future\mod.rs:84
  19: hyper::client::connect::http::{{impl}}::call_async::{{closure}}<hyper::client::connect::dns::GaiResolver>
             at {MyPath}\.cargo\registry\src\github.com-1ecc6299db9ec823\hyper-0.13.5\src\client\connect\http.rs:307
  20: core::future::from_generator::{{impl}}::poll<generator-0>
             at {MyPath}\.rustup\toolchains\nightly-x86_64-pc-windows-msvc\lib\rustlib\src\rust\src\libcore\future\mod.rs:66
  21: core::future::poll_with_context<core::future::from_generator::GenFuture<generator-0>>
             at {MyPath}\.rustup\toolchains\nightly-x86_64-pc-windows-msvc\lib\rustlib\src\rust\src\libcore\future\mod.rs:84
  22: hyper::client::connect::http::{{impl}}::call::{{closure}}<hyper::client::connect::dns::GaiResolver>
             at {MyPath}\.cargo\registry\src\github.com-1ecc6299db9ec823\hyper-0.13.5\src\client\connect\http.rs:248
  23: core::future::from_generator::{{impl}}::poll<generator-0>
             at {MyPath}\.rustup\toolchains\nightly-x86_64-pc-windows-msvc\lib\rustlib\src\rust\src\libcore\future\mod.rs:66
  24: core::future::future::{{impl}}::poll<alloc::boxed::Box<Future>>
             at {MyPath}\.rustup\toolchains\nightly-x86_64-pc-windows-msvc\lib\rustlib\src\rust\src\libcore\future\future.rs:118
  25: hyper::client::connect::http::{{impl}}::poll<hyper::client::connect::dns::GaiResolver>
             at {MyPath}\.cargo\registry\src\github.com-1ecc6299db9ec823\hyper-0.13.5\src\client\connect\http.rs:388
  26: futures_util::future::either::{{impl}}::poll<hyper::client::connect::http::HttpConnecting<hyper::client::connect::dns::GaiResolver>,hyper::client::connect::http::HttpConnecting<hyper::client::connect::dns::GaiResolver>>
             at {MyPath}\.cargo\registry\src\github.com-1ecc6299db9ec823\futures-util-0.3.4\src\future\either.rs:62
  27: core::future::poll_with_context<futures_util::future::either::Either<hyper::client::connect::http::HttpConnecting<hyper::client::connect::dns::GaiResolver>, hyper::client::connect::http::HttpConnecting<hyper::client::connect::dns::GaiResolver>>>
             at {MyPath}\.rustup\toolchains\nightly-x86_64-pc-windows-msvc\lib\rustlib\src\rust\src\libcore\future\mod.rs:84
  28: hyper_tls::client::{{impl}}::call::{{closure}}<reqwest::connect::HttpConnector>
             at {MyPath}\.cargo\registry\src\github.com-1ecc6299db9ec823\hyper-tls-0.4.1\src\client.rs:115
  29: core::future::from_generator::{{impl}}::poll<generator-0>
             at {MyPath}\.rustup\toolchains\nightly-x86_64-pc-windows-msvc\lib\rustlib\src\rust\src\libcore\future\mod.rs:66
  30: core::future::future::{{impl}}::poll<alloc::boxed::Box<Future>>
             at {MyPath}\.rustup\toolchains\nightly-x86_64-pc-windows-msvc\lib\rustlib\src\rust\src\libcore\future\future.rs:118
  31: hyper_tls::client::{{impl}}::poll<tokio::net::tcp::stream::TcpStream>
             at {MyPath}\.cargo\registry\src\github.com-1ecc6299db9ec823\hyper-tls-0.4.1\src\client.rs:144
  32: core::future::poll_with_context<hyper_tls::client::HttpsConnecting<tokio::net::tcp::stream::TcpStream>>
             at {MyPath}\.rustup\toolchains\nightly-x86_64-pc-windows-msvc\lib\rustlib\src\rust\src\libcore\future\mod.rs:84
  33: reqwest::connect::{{impl}}::connect_with_maybe_proxy::{{closure}}
             at {MyPath}\.cargo\registry\src\github.com-1ecc6299db9ec823\reqwest-0.10.4\src\connect.rs:346
  34: core::future::from_generator::{{impl}}::poll<generator-0>
             at {MyPath}\.rustup\toolchains\nightly-x86_64-pc-windows-msvc\lib\rustlib\src\rust\src\libcore\future\mod.rs:66
  35: core::future::poll_with_context<core::future::from_generator::GenFuture<generator-0>>
             at {MyPath}\.rustup\toolchains\nightly-x86_64-pc-windows-msvc\lib\rustlib\src\rust\src\libcore\future\mod.rs:84
  36: reqwest::connect::with_timeout::{{closure}}<reqwest::connect::Conn,core::future::from_generator::GenFuture<generator-0>>
             at {MyPath}\.cargo\registry\src\github.com-1ecc6299db9ec823\reqwest-0.10.4\src\connect.rs:500
  37: core::future::from_generator::{{impl}}::poll<generator-0>
             at {MyPath}\.rustup\toolchains\nightly-x86_64-pc-windows-msvc\lib\rustlib\src\rust\src\libcore\future\mod.rs:66
  38: core::future::future::{{impl}}::poll<alloc::boxed::Box<Future>>
             at {MyPath}\.rustup\toolchains\nightly-x86_64-pc-windows-msvc\lib\rustlib\src\rust\src\libcore\future\future.rs:118
  39: hyper::service::oneshot::{{impl}}::poll<reqwest::connect::Connector,http::uri::Uri>
             at {MyPath}\.cargo\registry\src\github.com-1ecc6299db9ec823\hyper-0.13.5\src\service\oneshot.rs:58
  40: futures_core::future::{{impl}}::try_poll<hyper::service::oneshot::Oneshot<reqwest::connect::Connector, http::uri::Uri>,reqwest::connect::Conn,alloc::boxed::Box<Error>>
             at {MyPath}\.cargo\registry\src\github.com-1ecc6299db9ec823\futures-core-0.3.4\src\future.rs:83
  41: futures_util::future::try_future::map_err::{{impl}}::poll<hyper::service::oneshot::Oneshot<reqwest::connect::Connector, http::uri::Uri>,fn(alloc::boxed::Box<Error>) -> hyper::error::Error,hyper::error::Error>
             at {MyPath}\.cargo\registry\src\github.com-1ecc6299db9ec823\futures-util-0.3.4\src\future\try_future\map_err.rs:43
  42: futures_core::future::{{impl}}::try_poll<futures_util::future::try_future::map_err::MapErr<hyper::service::oneshot::Oneshot<reqwest::connect::Connector, http::uri::Uri>, fn(alloc::boxed::Box<Error>) -> hyper::error::Error>,reqwest::connect::Conn,hyper::er
             at {MyPath}\.cargo\registry\src\github.com-1ecc6299db9ec823\futures-core-0.3.4\src\future.rs:83
  43: futures_util::future::try_future::try_chain::TryChain<futures_util::future::try_future::map_err::MapErr<hyper::service::oneshot::Oneshot<reqwest::connect::Connector, http::uri::Uri>, fn(alloc::boxed::Box<Error>) -> hyper::error::Error>, futures_util::futu
             at {MyPath}\.cargo\registry\src\github.com-1ecc6299db9ec823\futures-util-0.3.4\src\future\try_future\try_chain.rs:53
  44: futures_util::future::try_future::and_then::{{impl}}::poll<futures_util::future::try_future::map_err::MapErr<hyper::service::oneshot::Oneshot<reqwest::connect::Connector, http::uri::Uri>, fn(alloc::boxed::Box<Error>) -> hyper::error::Error>,futures_util::
             at {MyPath}\.cargo\registry\src\github.com-1ecc6299db9ec823\futures-util-0.3.4\src\future\try_future\and_then.rs:46
  45: futures_util::future::either::{{impl}}::poll<futures_util::future::try_future::and_then::AndThen<futures_util::future::try_future::map_err::MapErr<hyper::service::oneshot::Oneshot<reqwest::connect::Connector, http::uri::Uri>, fn(alloc::boxed::Box<Error>) 
             at {MyPath}\.cargo\registry\src\github.com-1ecc6299db9ec823\futures-util-0.3.4\src\future\either.rs:62
  46: hyper::common::lazy::{{impl}}::poll<closure-0,futures_util::future::either::Either<futures_util::future::try_future::and_then::AndThen<futures_util::future::try_future::map_err::MapErr<hyper::service::oneshot::Oneshot<reqwest::connect::Connector, http::ur
             at {MyPath}\.cargo\registry\src\github.com-1ecc6299db9ec823\hyper-0.13.5\src\common\lazy.rs:59
  47: futures_util::future::future::FutureExt::poll_unpin<hyper::common::lazy::Lazy<closure-0, futures_util::future::either::Either<futures_util::future::try_future::and_then::AndThen<futures_util::future::try_future::map_err::MapErr<hyper::service::oneshot::On
             at {MyPath}\.cargo\registry\src\github.com-1ecc6299db9ec823\futures-util-0.3.4\src\future\future\mod.rs:507
  48: futures_util::future::select::{{impl}}::poll<hyper::client::pool::Checkout<hyper::client::PoolClient<reqwest::async_impl::body::ImplStream>>,hyper::common::lazy::Lazy<closure-0, futures_util::future::either::Either<futures_util::future::try_future::and_th
             at {MyPath}\.cargo\registry\src\github.com-1ecc6299db9ec823\futures-util-0.3.4\src\future\select.rs:64
  49: futures_util::future::future::chain::Chain<futures_util::future::select::Select<hyper::client::pool::Checkout<hyper::client::PoolClient<reqwest::async_impl::body::ImplStream>>, hyper::common::lazy::Lazy<closure-0, futures_util::future::either::Either<futu
             at {MyPath}\.cargo\registry\src\github.com-1ecc6299db9ec823\futures-util-0.3.4\src\future\future\chain.rs:44
  50: futures_util::future::future::then::{{impl}}::poll<futures_util::future::select::Select<hyper::client::pool::Checkout<hyper::client::PoolClient<reqwest::async_impl::body::ImplStream>>, hyper::common::lazy::Lazy<closure-0, futures_util::future::either::Eit
             at {MyPath}\.cargo\registry\src\github.com-1ecc6299db9ec823\futures-util-0.3.4\src\future\future\then.rs:44
  51: futures_core::future::{{impl}}::try_poll<futures_util::future::future::then::Then<futures_util::future::select::Select<hyper::client::pool::Checkout<hyper::client::PoolClient<reqwest::async_impl::body::ImplStream>>, hyper::common::lazy::Lazy<closure-0, fu
             at {MyPath}\.cargo\registry\src\github.com-1ecc6299db9ec823\futures-core-0.3.4\src\future.rs:83
  52: futures_util::future::try_future::try_chain::TryChain<futures_util::future::future::then::Then<futures_util::future::select::Select<hyper::client::pool::Checkout<hyper::client::PoolClient<reqwest::async_impl::body::ImplStream>>, hyper::common::lazy::Lazy<
             at {MyPath}\.cargo\registry\src\github.com-1ecc6299db9ec823\futures-util-0.3.4\src\future\try_future\try_chain.rs:53
  53: futures_util::future::try_future::and_then::{{impl}}::poll<futures_util::future::future::then::Then<futures_util::future::select::Select<hyper::client::pool::Checkout<hyper::client::PoolClient<reqwest::async_impl::body::ImplStream>>, hyper::common::lazy::
             at {MyPath}\.cargo\registry\src\github.com-1ecc6299db9ec823\futures-util-0.3.4\src\future\try_future\and_then.rs:46
  54: hyper::client::{{impl}}::retryably_send_request::{{closure}}<reqwest::connect::Connector,reqwest::async_impl::body::ImplStream>
             at {MyPath}\.cargo\registry\src\github.com-1ecc6299db9ec823\hyper-0.13.5\src\client\mod.rs:253
  55: futures_util::future::poll_fn::{{impl}}::poll<core::result::Result<http::response::Response<hyper::body::body::Body>, hyper::error::Error>,closure-0>
             at {MyPath}\.cargo\registry\src\github.com-1ecc6299db9ec823\futures-util-0.3.4\src\future\poll_fn.rs:54
  56: core::future::future::{{impl}}::poll<alloc::boxed::Box<Future>>
             at {MyPath}\.rustup\toolchains\nightly-x86_64-pc-windows-msvc\lib\rustlib\src\rust\src\libcore\future\future.rs:118
  57: hyper::client::{{impl}}::poll
             at {MyPath}\.cargo\registry\src\github.com-1ecc6299db9ec823\hyper-0.13.5\src\client\mod.rs:604
  58: reqwest::async_impl::client::{{impl}}::poll
             at {MyPath}\.cargo\registry\src\github.com-1ecc6299db9ec823\reqwest-0.10.4\src\async_impl\client.rs:1276
  59: reqwest::async_impl::client::{{impl}}::poll
             at {MyPath}\.cargo\registry\src\github.com-1ecc6299db9ec823\reqwest-0.10.4\src\async_impl\client.rs:1255
  60: core::future::poll_with_context<reqwest::async_impl::client::Pending>
             at {MyPath}\.rustup\toolchains\nightly-x86_64-pc-windows-msvc\lib\rustlib\src\rust\src\libcore\future\mod.rs:84
  61: reqwest::get::{{closure}}<url::Url>
             at {MyPath}\.cargo\registry\src\github.com-1ecc6299db9ec823\reqwest-0.10.4\src\lib.rs:249
  62: core::future::from_generator::{{impl}}::poll<generator-0>
             at {MyPath}\.rustup\toolchains\nightly-x86_64-pc-windows-msvc\lib\rustlib\src\rust\src\libcore\future\mod.rs:66
  63: core::future::poll_with_context<core::future::from_generator::GenFuture<generator-0>>
             at {MyPath}\.rustup\toolchains\nightly-x86_64-pc-windows-msvc\lib\rustlib\src\rust\src\libcore\future\mod.rs:84
  64: SearchEngine::handle_url::{{closure}}
             at .\src\main.rs:21
  65: core::future::from_generator::{{impl}}::poll<generator-0>
             at {MyPath}\.rustup\toolchains\nightly-x86_64-pc-windows-msvc\lib\rustlib\src\rust\src\libcore\future\mod.rs:66
  66: tokio::runtime::task::core::{{impl}}::poll::{{closure}}<core::future::from_generator::GenFuture<generator-0>,alloc::sync::Arc<tokio::runtime::thread_pool::worker::Worker>>
             at {MyPath}\.cargo\registry\src\github.com-1ecc6299db9ec823\tokio-0.2.19\src\runtime\task\core.rs:163
  67: tokio::loom::std::unsafe_cell::UnsafeCell<tokio::runtime::task::core::Stage<core::future::from_generator::GenFuture<generator-0>>>::with_mut<tokio::runtime::task::core::Stage<core::future::from_generator::GenFuture<generator-0>>,core::task::poll::Poll<cor
             at {MyPath}\.cargo\registry\src\github.com-1ecc6299db9ec823\tokio-0.2.19\src\loom\std\unsafe_cell.rs:14
  68: tokio::runtime::task::core::Core<core::future::from_generator::GenFuture<generator-0>, alloc::sync::Arc<tokio::runtime::thread_pool::worker::Worker>>::poll<core::future::from_generator::GenFuture<generator-0>,alloc::sync::Arc<tokio::runtime::thread_pool::
             at {MyPath}\.cargo\registry\src\github.com-1ecc6299db9ec823\tokio-0.2.19\src\runtime\task\core.rs:148
  69: tokio::runtime::task::harness::{{impl}}::poll::{{closure}}<core::future::from_generator::GenFuture<generator-0>,alloc::sync::Arc<tokio::runtime::thread_pool::worker::Worker>>
             at {MyPath}\.cargo\registry\src\github.com-1ecc6299db9ec823\tokio-0.2.19\src\runtime\task\harness.rs:108
  70: core::ops::function::FnOnce::call_once<closure-0,()>
             at {MyPath}\.rustup\toolchains\nightly-x86_64-pc-windows-msvc\lib\rustlib\src\rust\src\libcore\ops\function.rs:232
  71: std::panic::{{impl}}::call_once<core::task::poll::Poll<core::result::Result<core::result::Result<(), alloc::boxed::Box<Error>>, tokio::runtime::task::error::JoinError>>,closure-0>
             at {MyPath}\.rustup\toolchains\nightly-x86_64-pc-windows-msvc\lib\rustlib\src\rust\src\libstd\panic.rs:318
  72: std::panicking::try::do_call<std::panic::AssertUnwindSafe<closure-0>,core::task::poll::Poll<core::result::Result<core::result::Result<(), alloc::boxed::Box<Error>>, tokio::runtime::task::error::JoinError>>>
             at {MyPath}\.rustup\toolchains\nightly-x86_64-pc-windows-msvc\lib\rustlib\src\rust\src\libstd\panicking.rs:331
  73: std::panicking::try::do_catch<std::panic::AssertUnwindSafe<closure-0>,core::task::poll::Poll<core::result::Result<core::result::Result<(), alloc::boxed::Box<Error>>, tokio::runtime::task::error::JoinError>>>
  74: std::panicking::try<core::task::poll::Poll<core::result::Result<core::result::Result<(), alloc::boxed::Box<Error>>, tokio::runtime::task::error::JoinError>>,std::panic::AssertUnwindSafe<closure-0>>
             at {MyPath}\.rustup\toolchains\nightly-x86_64-pc-windows-msvc\lib\rustlib\src\rust\src\libstd\panicking.rs:274
  75: std::panic::catch_unwind<std::panic::AssertUnwindSafe<closure-0>,core::task::poll::Poll<core::result::Result<core::result::Result<(), alloc::boxed::Box<Error>>, tokio::runtime::task::error::JoinError>>>
             at {MyPath}\.rustup\toolchains\nightly-x86_64-pc-windows-msvc\lib\rustlib\src\rust\src\libstd\panic.rs:394
  76: tokio::runtime::task::harness::Harness<core::future::from_generator::GenFuture<generator-0>, alloc::sync::Arc<tokio::runtime::thread_pool::worker::Worker>>::poll<core::future::from_generator::GenFuture<generator-0>,alloc::sync::Arc<tokio::runtime::thread_
             at {MyPath}\.cargo\registry\src\github.com-1ecc6299db9ec823\tokio-0.2.19\src\runtime\task\harness.rs:84
  77: tokio::runtime::task::raw::poll<core::future::from_generator::GenFuture<generator-0>,alloc::sync::Arc<tokio::runtime::thread_pool::worker::Worker>>
             at {MyPath}\.cargo\registry\src\github.com-1ecc6299db9ec823\tokio-0.2.19\src\runtime\task\raw.rs:104
  78: tokio::runtime::task::raw::RawTask::poll
             at {MyPath}\.cargo\registry\src\github.com-1ecc6299db9ec823\tokio-0.2.19\src\runtime\task\raw.rs:66
  79: tokio::runtime::task::Notified<alloc::sync::Arc<tokio::runtime::thread_pool::worker::Worker>>::run<alloc::sync::Arc<tokio::runtime::thread_pool::worker::Worker>>
             at {MyPath}\.cargo\registry\src\github.com-1ecc6299db9ec823\tokio-0.2.19\src\runtime\task\mod.rs:169
  80: tokio::runtime::thread_pool::worker::{{impl}}::run_task::{{closure}}
             at {MyPath}\.cargo\registry\src\github.com-1ecc6299db9ec823\tokio-0.2.19\src\runtime\thread_pool\worker.rs:353
  81: tokio::coop::budget::{{closure}}<closure-0,core::result::Result<alloc::boxed::Box<tokio::runtime::thread_pool::worker::Core>, ()>>
             at {MyPath}\.cargo\registry\src\github.com-1ecc6299db9ec823\tokio-0.2.19\src\coop.rs:97
  82: std::thread::local::LocalKey<core::cell::Cell<usize>>::try_with<core::cell::Cell<usize>,closure-0,core::result::Result<alloc::boxed::Box<tokio::runtime::thread_pool::worker::Core>, ()>>
             at {MyPath}\.rustup\toolchains\nightly-x86_64-pc-windows-msvc\lib\rustlib\src\rust\src\libstd\thread\local.rs:263
  83: std::thread::local::LocalKey<core::cell::Cell<usize>>::with<core::cell::Cell<usize>,closure-0,core::result::Result<alloc::boxed::Box<tokio::runtime::thread_pool::worker::Core>, ()>>
             at {MyPath}\.rustup\toolchains\nightly-x86_64-pc-windows-msvc\lib\rustlib\src\rust\src\libstd\thread\local.rs:239
  84: tokio::coop::budget
             at {MyPath}\.cargo\registry\src\github.com-1ecc6299db9ec823\tokio-0.2.19\src\coop.rs:79
  85: tokio::runtime::thread_pool::worker::Context::run_task
             at {MyPath}\.cargo\registry\src\github.com-1ecc6299db9ec823\tokio-0.2.19\src\runtime\thread_pool\worker.rs:352
  86: tokio::runtime::thread_pool::worker::Context::run
             at {MyPath}\.cargo\registry\src\github.com-1ecc6299db9ec823\tokio-0.2.19\src\runtime\thread_pool\worker.rs:324
  87: tokio::runtime::thread_pool::worker::run::{{closure}}
             at {MyPath}\.cargo\registry\src\github.com-1ecc6299db9ec823\tokio-0.2.19\src\runtime\thread_pool\worker.rs:309
  88: tokio::macros::scoped_tls::ScopedKey<tokio::runtime::thread_pool::worker::Context>::set<tokio::runtime::thread_pool::worker::Context,closure-0,()>
             at {MyPath}\.cargo\registry\src\github.com-1ecc6299db9ec823\tokio-0.2.19\src\macros\scoped_tls.rs:64
  89: tokio::runtime::thread_pool::worker::run
             at {MyPath}\.cargo\registry\src\github.com-1ecc6299db9ec823\tokio-0.2.19\src\runtime\thread_pool\worker.rs:306
  90: tokio::runtime::thread_pool::worker::{{impl}}::launch::{{closure}}
             at {MyPath}\.cargo\registry\src\github.com-1ecc6299db9ec823\tokio-0.2.19\src\runtime\thread_pool\worker.rs:285
  91: tokio::runtime::blocking::task::{{impl}}::poll<closure-0,()>
             at {MyPath}\.cargo\registry\src\github.com-1ecc6299db9ec823\tokio-0.2.19\src\runtime\blocking\task.rs:38
  92: tokio::runtime::task::core::{{impl}}::poll::{{closure}}<tokio::runtime::blocking::task::BlockingTask<closure-0>,tokio::runtime::blocking::schedule::NoopSchedule>
             at {MyPath}\.cargo\registry\src\github.com-1ecc6299db9ec823\tokio-0.2.19\src\runtime\task\core.rs:163
  93: tokio::loom::std::unsafe_cell::UnsafeCell<tokio::runtime::task::core::Stage<tokio::runtime::blocking::task::BlockingTask<closure-0>>>::with_mut<tokio::runtime::task::core::Stage<tokio::runtime::blocking::task::BlockingTask<closure-0>>,core::task::poll::Po
             at {MyPath}\.cargo\registry\src\github.com-1ecc6299db9ec823\tokio-0.2.19\src\loom\std\unsafe_cell.rs:14
  94: tokio::runtime::task::core::Core<tokio::runtime::blocking::task::BlockingTask<closure-0>, tokio::runtime::blocking::schedule::NoopSchedule>::poll<tokio::runtime::blocking::task::BlockingTask<closure-0>,tokio::runtime::blocking::schedule::NoopSchedule>
             at {MyPath}\.cargo\registry\src\github.com-1ecc6299db9ec823\tokio-0.2.19\src\runtime\task\core.rs:148
  95: tokio::runtime::task::harness::{{impl}}::poll::{{closure}}<tokio::runtime::blocking::task::BlockingTask<closure-0>,tokio::runtime::blocking::schedule::NoopSchedule>
             at {MyPath}\.cargo\registry\src\github.com-1ecc6299db9ec823\tokio-0.2.19\src\runtime\task\harness.rs:108
  96: core::ops::function::FnOnce::call_once<closure-0,()>
             at {MyPath}\.rustup\toolchains\nightly-x86_64-pc-windows-msvc\lib\rustlib\src\rust\src\libcore\ops\function.rs:232
  97: std::panic::{{impl}}::call_once<core::task::poll::Poll<core::result::Result<(), tokio::runtime::task::error::JoinError>>,closure-0>
             at {MyPath}\.rustup\toolchains\nightly-x86_64-pc-windows-msvc\lib\rustlib\src\rust\src\libstd\panic.rs:318
  98: std::panicking::try::do_call<std::panic::AssertUnwindSafe<closure-0>,core::task::poll::Poll<core::result::Result<(), tokio::runtime::task::error::JoinError>>>
             at {MyPath}\.rustup\toolchains\nightly-x86_64-pc-windows-msvc\lib\rustlib\src\rust\src\libstd\panicking.rs:331
  99: core::result::{{impl}}::into_result<std::sync::mutex::MutexGuard<()>,std::sys_common::poison::PoisonError<std::sync::mutex::MutexGuard<()>>>
 100: std::panicking::try<core::task::poll::Poll<core::result::Result<(), tokio::runtime::task::error::JoinError>>,std::panic::AssertUnwindSafe<closure-0>>
             at {MyPath}\.rustup\toolchains\nightly-x86_64-pc-windows-msvc\lib\rustlib\src\rust\src\libstd\panicking.rs:274
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.

Consider the following code:

tokio::spawn(handle_url(url)); // Crashed
handle_url(url).await; // Ok

I have no idea why in tokio::spawn it crashed !!

When rustc compiles an async function it essentially generates a big enum with variants for each await point holding things like local variables and the future that is being awaited.

If you try to use recursion without an extra level of indirection then trying to await on handle_url(&child_url) means one of the enum variants would contain the future for handle_url... which means handle_url's enum would contain an instance of itself (which would contain an instance of itself, which would ...).

It's not possible to know the layout of such a recursive type, so the compiler will give up and tells you to use some indirection which has a known size (e.g. a Box).

@Michael-F-Bryan
Okay, but how can I .await on recursive call in the same function ?

Does something like handle_url(&child_url).boxed().await work?

Yes, except the function itself returns a Boxed & Pinned future...

fn handle_url(url: String) -> Pin<Box<dyn Future<Output=Result<(), ()>> + Send>> {
    Box::pin(async move {
        if url.len() <= 1 {
            return Ok(());
        }
        
        let child_url = (&url[1..]).to_string();
        
        tokio::spawn(handle_url(child_url));
        
        Ok(())
    })
}

Playground: https://play.rust-lang.org/?version=stable&mode=release&edition=2018&gist=f142c2b075bfa825351ca71100b06ab0

I just googled "rust async await recursion" and the first result it showed me was the Recursion chapter from The Async Book and they propose the same workaround:

In order to allow this, we have to introduce an indirection using Box . Unfortunately, compiler limitations mean that just wrapping the calls to recursive() in Box::pin isn't enough. To make this work, we have to make recursive into a non- async function which returns a .boxed() async block:

use futures::future::{BoxFuture, FutureExt};

fn recursive() -> BoxFuture<'static, ()> {
    async move {
        recursive().await;
        recursive().await;
    }.boxed()
}

You mean something like the following code:

enum FutureResult {
    HandleUrl2,
    HandleUrl,
}

fn do_some_stuff(url: &str) -> FutureResult {
    return FutureResult::HandleUrl2;
}

fn handle_url(url: &str) -> FutureResult {
    do_some_stuff(url);
    if url == "Some url" {
        return FutureResult::HandleUrl;
    }
    let child_url = "Some url";
    return handle_url(child_url);
}

But I do not see any issues with such approach !?

Right, the async keyword is just syntactic sugar that turns the call into an impl Future

The example you've shown isn't correct. Each async function is compiled into its own type.

// This function:
async fn foo() {
    step_one().await;
    step_two().await;
}
// generates a type like this:
enum Foo {
    First(StepOne),
    Second(StepTwo),
}

// So this function:
async fn recursive() {
    recursive().await;
    recursive().await;
}

// generates a type like this:
enum Recursive {
    First(Recursive),
    Second(Recursive),
}

(quoting the first section in the Async Book's Recursion chapter)

No it does not work (:

It's not only boxing the future, it must be pinned too... I've corrected my example in post #14.

BoxFuture works, but what if I need the following:

async fn recursive() -> BoxFuture<'static, ()> {
   // Await on some other function
    async move {
        recursive().await;
        recursive().await;
    }.boxed()
}

Then it does not work !!

you shouldn't add the async keyword to the function, doing that makes the future return a future.
BoxFuture is a future on it's own, and it can be awaited.

1 Like

To expand on @naim's comment:

use futures::future::{BoxFuture, FutureExt};

fn recursive() -> BoxFuture<'static, ()> {
    async move {
        recursive().await;
        recursive().await;
    }
    .boxed()
}

(playground)

Put all of your awaits into the async block.

fn recursive() -> BoxFuture<'static, ()> {
    async move {
        // Await on some other function

        recursive().await;
        recursive().await;
    }.boxed()
}

But it is possible to handle with generating the following enum:

async step_one() -> u8 {
    1u8
}

async step_third() -> u32 {
    1u32
}

// So this function:
async fn recursive() {
    step_one().await;
    recursive().await;
    step_third().await;
    recursive().await;
}

// generates types like this:
enum RecursiveHelper {
    First(u8),
    Third(u32),
}

enum Recursive {
    First(u8),
    SecondSelfCall(RecursiveHelper),
    Third(u32),
    FourthSelfCall(RecursiveHelper),
}

I've just broken recursion and all should work !!
And I do not get why it is not implemented in such way ?
Is there any other technical issues ?

I can't see how it's true that your example async function should desugar to those two enums; Every call to recursive needs the full state. Which is recursive by definition. Break the recursion with indirection, which is what has been shown several times already.

It is hard to make such indirection and it is not readable at all !!

Take a look at example that I show above ...
Why t is not implemented in this way ?

The enum presented isn't actually meant to be for the programmer to write, It's just to show you what the compiler may emit.

enum FuncStates {
    State1{ /* state data */ },
    State2{ /* state data */ },
    State3{ /* state data */ },
   /* etc... */
}

You need to create a type that the compiler won't try to add to the imaginary enum (because if it does, it would be adding the enum to itself - which is not allowed).

enum States {
   State1 {},
   State2 { x: States }, // <- not allowed, compiler won't be able to find the size. It's infinite...
    /* etc... */
}

It is possible to add indirection by adding an indirect type:

enum States {
    State1 {},
    State2 { x: Box<States> }, // this will compile, because a Box is a pointer.
}

Rust requires a Box for this to be possible, and tokio's executor's spawn function requires functions to be Pin & Send, this example complies with all these requirements: