Newb: Tokio::JoinSet and Hickory-Resolver::Resolver Tokio runtimes interfering

Hi all, complete Rust newb here. I'm trying to make an async DNS resolver with a limiter on how many async threads get spawned. I've created a minimal reproducible example below, and the runtime error is below that.

Hickory-Resolver uses Tokio runtime under the hood, and I'm also using Tokio runtime for spawning threads. It seems these two interfere with each other and I'm not sure how to handle it. I'm assuming there's a way to pass one runtime into the other, but I can't figure that out.

Has anyone else ran into this, or can help out there?

#[tokio::main]
async fn main() -> Result<(),()> {

    let max_async_threads = 1;
    let mut fqdns = Vec::<String>::new();

    while fqdns.len() < 2 {
        fqdns.push("google.com.".to_string());
    }

    let mut join_set = JoinSet::<(String)>::new();
    for fqdn in fqdns {
        
        while join_set.len() >= max_async_threads {
            let result = join_set.join_next().await.expect("Async finsished").expect("DNS resolves");
            println!("{}", result);
        }

        join_set.spawn(some_async(fqdn));
    }

    while let Some(result) = join_set.join_next().await {
        let address = result.expect("DNS to return");
        println!("{}", address);
    }
    
    Ok(())
}

async fn some_async(fqdn: String) -> String {
    let resolver: Resolver = Resolver::new(ResolverConfig::default(), ResolverOpts::default()).unwrap();
    let response: Ipv4Lookup = resolver.ipv4_lookup(fqdn).unwrap();
    let address = response.iter().next().expect("addresses returned");
    address.to_string()
}
thread 'tokio-runtime-worker' panicked at C:\Users\kytravel\.cargo\registry\src\index.crates.io-6f17d22bba15001f\hickory-resolver-0.24.0\src\resolver.rs:149:5:
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.
stack backtrace:
   0: rust_begin_unwind
             at /rustc/82e1608dfa6e0b5569232559e3d385fea5a93112/library\std\src/panicking.rs:645:5
   1: core::panicking::panic_fmt
             at /rustc/82e1608dfa6e0b5569232559e3d385fea5a93112/library\core\src/panicking.rs:72:14
   2: tokio::runtime::context::runtime::enter_runtime
             at C:\Users\kytravel\.cargo\registry\src\index.crates.io-6f17d22bba15001f\tokio-1.36.0\src\runtime\context\runtime.rs:68:5
   3: tokio::runtime::scheduler::current_thread::CurrentThread::block_on
             at C:\Users\kytravel\.cargo\registry\src\index.crates.io-6f17d22bba15001f\tokio-1.36.0\src\runtime\scheduler\current_thread\mod.rs:167:9
   4: tokio::runtime::runtime::Runtime::block_on
             at C:\Users\kytravel\.cargo\registry\src\index.crates.io-6f17d22bba15001f\tokio-1.36.0\src\runtime\runtime.rs:348:47
   5: hickory_resolver::resolver::Resolver::ipv4_lookup
             at C:\Users\kytravel\.cargo\registry\src\index.crates.io-6f17d22bba15001f\hickory-resolver-0.24.0\src\resolver.rs:52:13
   6: zone_reader::some_async::{{closure}}
             at .\src\main.rs:58:32
   7: tokio::runtime::task::core::Core<T,S>::poll::{{closure}}
             at C:\Users\kytravel\.cargo\registry\src\index.crates.io-6f17d22bba15001f\tokio-1.36.0\src\runtime\task\core.rs:328:17
   8: tokio::loom::std::unsafe_cell::UnsafeCell<T>::with_mut
             at C:\Users\kytravel\.cargo\registry\src\index.crates.io-6f17d22bba15001f\tokio-1.36.0\src\loom\std\unsafe_cell.rs:16:9
   9: tokio::runtime::task::core::Core<T,S>::poll
             at C:\Users\kytravel\.cargo\registry\src\index.crates.io-6f17d22bba15001f\tokio-1.36.0\src\runtime\task\core.rs:317:13
  10: tokio::runtime::task::harness::poll_future::{{closure}}
             at C:\Users\kytravel\.cargo\registry\src\index.crates.io-6f17d22bba15001f\tokio-1.36.0\src\runtime\task\harness.rs:485:19
  11: <core::panic::unwind_safe::AssertUnwindSafe<F> as core::ops::function::FnOnce<()>>::call_once
             at /rustc/82e1608dfa6e0b5569232559e3d385fea5a93112\library\core\src\panic/unwind_safe.rs:272:9
  12: std::panicking::try::do_call
             at /rustc/82e1608dfa6e0b5569232559e3d385fea5a93112\library\std\src/panicking.rs:552:40
  13: __rust_try
  14: std::panicking::try
             at /rustc/82e1608dfa6e0b5569232559e3d385fea5a93112\library\std\src/panicking.rs:516:19
  15: std::panic::catch_unwind
             at /rustc/82e1608dfa6e0b5569232559e3d385fea5a93112\library\std\src/panic.rs:142:14
  16: tokio::runtime::task::harness::poll_future
             at C:\Users\kytravel\.cargo\registry\src\index.crates.io-6f17d22bba15001f\tokio-1.36.0\src\runtime\task\harness.rs:473:18
  17: tokio::runtime::task::harness::Harness<T,S>::poll_inner
             at C:\Users\kytravel\.cargo\registry\src\index.crates.io-6f17d22bba15001f\tokio-1.36.0\src\runtime\task\harness.rs:208:27
  18: tokio::runtime::task::harness::Harness<T,S>::poll
             at C:\Users\kytravel\.cargo\registry\src\index.crates.io-6f17d22bba15001f\tokio-1.36.0\src\runtime\task\harness.rs:153:15
  19: tokio::runtime::task::raw::poll
             at C:\Users\kytravel\.cargo\registry\src\index.crates.io-6f17d22bba15001f\tokio-1.36.0\src\runtime\task\raw.rs:271:5
  20: tokio::runtime::task::raw::RawTask::poll
             at C:\Users\kytravel\.cargo\registry\src\index.crates.io-6f17d22bba15001f\tokio-1.36.0\src\runtime\task\raw.rs:201:18
  21: tokio::runtime::task::LocalNotified<S>::run
             at C:\Users\kytravel\.cargo\registry\src\index.crates.io-6f17d22bba15001f\tokio-1.36.0\src\runtime\task\mod.rs:416:9
  22: tokio::runtime::scheduler::multi_thread::worker::Context::run_task::{{closure}}
             at C:\Users\kytravel\.cargo\registry\src\index.crates.io-6f17d22bba15001f\tokio-1.36.0\src\runtime\scheduler\multi_thread\worker.rs:576:13
  23: tokio::runtime::coop::with_budget
             at C:\Users\kytravel\.cargo\registry\src\index.crates.io-6f17d22bba15001f\tokio-1.36.0\src\runtime\coop.rs:107:5
  24: tokio::runtime::coop::budget
             at C:\Users\kytravel\.cargo\registry\src\index.crates.io-6f17d22bba15001f\tokio-1.36.0\src\runtime\coop.rs:73:5
  25: tokio::runtime::scheduler::multi_thread::worker::Context::run_task
             at C:\Users\kytravel\.cargo\registry\src\index.crates.io-6f17d22bba15001f\tokio-1.36.0\src\runtime\scheduler\multi_thread\worker.rs:575:9
  26: tokio::runtime::scheduler::multi_thread::worker::Context::run
             at C:\Users\kytravel\.cargo\registry\src\index.crates.io-6f17d22bba15001f\tokio-1.36.0\src\runtime\scheduler\multi_thread\worker.rs:526:24
  27: tokio::runtime::scheduler::multi_thread::worker::run::{{closure}}::{{closure}}
             at C:\Users\kytravel\.cargo\registry\src\index.crates.io-6f17d22bba15001f\tokio-1.36.0\src\runtime\scheduler\multi_thread\worker.rs:491:21
  28: tokio::runtime::context::scoped::Scoped<T>::set
             at C:\Users\kytravel\.cargo\registry\src\index.crates.io-6f17d22bba15001f\tokio-1.36.0\src\runtime\context\scoped.rs:40:9
  29: tokio::runtime::context::set_scheduler::{{closure}}
             at C:\Users\kytravel\.cargo\registry\src\index.crates.io-6f17d22bba15001f\tokio-1.36.0\src\runtime\context.rs:176:26
  30: std::thread::local::LocalKey<T>::try_with
             at /rustc/82e1608dfa6e0b5569232559e3d385fea5a93112\library\std\src\thread/local.rs:270:16
  31: std::thread::local::LocalKey<T>::with
             at /rustc/82e1608dfa6e0b5569232559e3d385fea5a93112\library\std\src\thread/local.rs:246:9
  32: tokio::runtime::context::set_scheduler
             at C:\Users\kytravel\.cargo\registry\src\index.crates.io-6f17d22bba15001f\tokio-1.36.0\src\runtime\context.rs:176:9
  33: tokio::runtime::scheduler::multi_thread::worker::run::{{closure}}
             at C:\Users\kytravel\.cargo\registry\src\index.crates.io-6f17d22bba15001f\tokio-1.36.0\src\runtime\scheduler\multi_thread\worker.rs:486:9
  34: tokio::runtime::context::runtime::enter_runtime
             at C:\Users\kytravel\.cargo\registry\src\index.crates.io-6f17d22bba15001f\tokio-1.36.0\src\runtime\context\runtime.rs:65:16
  35: tokio::runtime::scheduler::multi_thread::worker::run
             at C:\Users\kytravel\.cargo\registry\src\index.crates.io-6f17d22bba15001f\tokio-1.36.0\src\runtime\scheduler\multi_thread\worker.rs:478:5
  36: tokio::runtime::scheduler::multi_thread::worker::Launch::launch::{{closure}}
             at C:\Users\kytravel\.cargo\registry\src\index.crates.io-6f17d22bba15001f\tokio-1.36.0\src\runtime\scheduler\multi_thread\worker.rs:447:45
  37: <tokio::runtime::blocking::task::BlockingTask<T> as core::future::future::Future>::poll
             at C:\Users\kytravel\.cargo\registry\src\index.crates.io-6f17d22bba15001f\tokio-1.36.0\src\runtime\blocking\task.rs:42:21
  38: tokio::runtime::task::core::Core<T,S>::poll::{{closure}}
             at C:\Users\kytravel\.cargo\registry\src\index.crates.io-6f17d22bba15001f\tokio-1.36.0\src\runtime\task\core.rs:328:17
  39: tokio::loom::std::unsafe_cell::UnsafeCell<T>::with_mut
             at C:\Users\kytravel\.cargo\registry\src\index.crates.io-6f17d22bba15001f\tokio-1.36.0\src\loom\std\unsafe_cell.rs:16:9
  40: tokio::runtime::task::core::Core<T,S>::poll
             at C:\Users\kytravel\.cargo\registry\src\index.crates.io-6f17d22bba15001f\tokio-1.36.0\src\runtime\task\core.rs:317:13
  41: tokio::runtime::task::harness::poll_future::{{closure}}
             at C:\Users\kytravel\.cargo\registry\src\index.crates.io-6f17d22bba15001f\tokio-1.36.0\src\runtime\task\harness.rs:485:19
  42: <core::panic::unwind_safe::AssertUnwindSafe<F> as core::ops::function::FnOnce<()>>::call_once
             at /rustc/82e1608dfa6e0b5569232559e3d385fea5a93112\library\core\src\panic/unwind_safe.rs:272:9
  43: std::panicking::try::do_call
             at /rustc/82e1608dfa6e0b5569232559e3d385fea5a93112\library\std\src/panicking.rs:552:40
  44: __rust_try
  45: std::panicking::try
             at /rustc/82e1608dfa6e0b5569232559e3d385fea5a93112\library\std\src/panicking.rs:516:19
  46: std::panic::catch_unwind
             at /rustc/82e1608dfa6e0b5569232559e3d385fea5a93112\library\std\src/panic.rs:142:14
  47: tokio::runtime::task::harness::poll_future
             at C:\Users\kytravel\.cargo\registry\src\index.crates.io-6f17d22bba15001f\tokio-1.36.0\src\runtime\task\harness.rs:473:18
  48: tokio::runtime::task::harness::Harness<T,S>::poll_inner
             at C:\Users\kytravel\.cargo\registry\src\index.crates.io-6f17d22bba15001f\tokio-1.36.0\src\runtime\task\harness.rs:208:27
  49: tokio::runtime::task::harness::Harness<T,S>::poll
             at C:\Users\kytravel\.cargo\registry\src\index.crates.io-6f17d22bba15001f\tokio-1.36.0\src\runtime\task\harness.rs:153:15
  50: tokio::runtime::task::raw::poll
             at C:\Users\kytravel\.cargo\registry\src\index.crates.io-6f17d22bba15001f\tokio-1.36.0\src\runtime\task\raw.rs:271:5
  51: tokio::runtime::task::raw::RawTask::poll
             at C:\Users\kytravel\.cargo\registry\src\index.crates.io-6f17d22bba15001f\tokio-1.36.0\src\runtime\task\raw.rs:201:18
  52: tokio::runtime::task::UnownedTask<S>::run
             at C:\Users\kytravel\.cargo\registry\src\index.crates.io-6f17d22bba15001f\tokio-1.36.0\src\runtime\task\mod.rs:453:9
  53: tokio::runtime::blocking::pool::Task::run
             at C:\Users\kytravel\.cargo\registry\src\index.crates.io-6f17d22bba15001f\tokio-1.36.0\src\runtime\blocking\pool.rs:159:9
  54: tokio::runtime::blocking::pool::Inner::run
             at C:\Users\kytravel\.cargo\registry\src\index.crates.io-6f17d22bba15001f\tokio-1.36.0\src\runtime\blocking\pool.rs:513:17
  55: tokio::runtime::blocking::pool::Spawner::spawn_thread::{{closure}}
             at C:\Users\kytravel\.cargo\registry\src\index.crates.io-6f17d22bba15001f\tokio-1.36.0\src\runtime\blocking\pool.rs:471:13
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
thread 'main' panicked at src\main.rs:41:79:
DNS resolves: JoinError::Panic(Id(17), ...)

Can you describe what error or symptom of interference you are observing?

FYI, I opened an issue with Hickory and the main contributor got back near instantly.

The correct Hickory object is the AsyncResolver::tokio

#[tokio::main]
async fn main() -> Result<(),()> {
    let max_async_threads = 10;
    let mut fqdns = Vec::<String>::new();

    while fqdns.len() < 100 {
        fqdns.push("google.com.".to_string());
    }

    let mut join_set = JoinSet::<(String)>::new();
    for fqdn in fqdns {
        
        while join_set.len() >= max_async_threads {
            let result = join_set.join_next().await.expect("Async to return").expect("DNS to resolve");
            println!("{}", result);
        }

        join_set.spawn(some_async(fqdn));
    }

    while let Some(result) = join_set.join_next().await {
        let address = result.expect("DNS to return");
        println!("{}", address);
    }
    
    Ok(())
}

async fn some_async(fqdn: String) -> String {
    let resolver = AsyncResolver::tokio(ResolverConfig::default(), ResolverOpts::default());
    let response: Ipv4Lookup = resolver.ipv4_lookup(fqdn).await.unwrap();
    let address = response.iter().next().expect("no addresses returned!");
    address.to_string()
}