If you use a new runtime and the lazy static is first used within the context of an existing runtime, like in this example:
use lazy_static::lazy_static;
use mongodb::Client;
lazy_static! {
static ref CLIENT: Client = {
tokio::runtime::Runtime::new().unwrap().block_on(async {
let uri = std::env::var("MONGO_URL").unwrap();
let client = Client::with_uri_str(&uri).await.unwrap();
client
})
};
}
#[tokio::main]
async fn main() {
let _db = CLIENT.database("local");
}
You'll get the error mentioned:
thread 'main' panicked at '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.', C:\Users\kmdreko\.cargo\registry\src\github.com-1ecc6299db9ec823\tokio-1.6.1\src\runtime\enter.rs:39:9
You may be able to circumvent this by using a different runtime (futures vs tokio vs async-std) but that's not ideal since it'd still be blocking the underlying one.
A relatively straight-forward way to solve this is not try to do it lazily and initialize it immediately in main. That way you can utilize an asynchronous runtime directly and not worry about needing one elsewhere:
use mongodb::Client;
use once_cell::sync::OnceCell;
static CLIENT: OnceCell<Client> = OnceCell::new();
#[tokio::main]
async fn main() {
let uri = std::env::var("MONGO_URL").unwrap();
let client = Client::with_uri_str(&uri).await.unwrap();
CLIENT.set(client).unwrap();
let _db = CLIENT.get().unwrap().database("local");
}
This can be done via OnceCell (as seen above) or something like a RwLock if necessary.
The most direct answer to what you're trying to achieve would be to use the async_once crate, which makes it use the receiver's runtime to drive the asynchronous function.
use async_once::AsyncOnce;
use lazy_static::lazy_static;
use mongodb::Client;
lazy_static! {
static ref CLIENT: AsyncOnce<Client> = AsyncOnce::new(async {
let uri = std::env::var("MONGO_URL").unwrap();
let client = Client::with_uri_str(&uri).await.unwrap();
client
});
}
#[tokio::main]
async fn main() {
let _db = CLIENT.get().await.database("local");
}
This assumes all or nearly all uses of the client will be in asynchronous contexts.