如何在 rocket.rs 的启动阶段正确执行 long-运行 数据库操作?
How to properly exec a long-running database operation during the launching phase in rocket.rs?
我正在尝试进行一个长 运行(~1 分钟)的函数调用,该函数调用查询数据库并构造一些数据对象以供将来使用。但是如果我在启动函数中创建一个 postgres::Client
,它会给我一个运行时恐慌。
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.'
最小的示例代码片段如下所示:
use postgres::{Client, NoTls};
use my_crate::my_libs::fill_data_model_from_db;
#[macro_use] extern crate rocket;
#[get("/world")]
fn world() -> &'static str {
"Hello, world!"
}
#[launch]
fn rocket() -> _ {
let mut client: Client = Client::connect("host=localhost dbname=testdb", NoTls).unwrap();
// long running db queries for data preparation
// let d = fill_data_model_from_db(&mut client);
// will use State to encapsulate `d`
rocket::build().mount("/hello", routes![world])
}
我有点奇怪,虽然postgres::Client
实际上是一个synchronous PostgreSQL client
,正如它的文档所说,为什么创建它会导致嵌套的tokio运行时问题?我已经看过 rocket_db_pools,但无法弄清楚数据库池在这里有何帮助。我对 Rust 和 Rocket 还是很陌生。任何提示或帮助都将非常受欢迎!非常感谢!
postgres::Client
从调用者的角度来看是同步的,但它通过创建运行时并在内部调用异步 API 来工作。
在这种情况下,解决方案非常简单:只需将 rocket
函数设为 async
并使用异步 Postgres API:
use tokio_postgres::{Client, NoTls};
#[macro_use] extern crate rocket;
#[get("/world")]
fn world() -> &'static str {
"Hello, world!"
}
#[launch]
async fn rocket() -> _ {
let (client, connection) = tokio_postgres::connect("host=localhost dbname=testdb", NoTls).await.unwrap();
tokio::spawn(async move {
if let Err(e) = connection.await {
eprintln!("connection error: {}", e);
}
});
// use `client` to make asynchronous DB requests
rocket::build().mount("/hello", routes![world])
}
我正在尝试进行一个长 运行(~1 分钟)的函数调用,该函数调用查询数据库并构造一些数据对象以供将来使用。但是如果我在启动函数中创建一个 postgres::Client
,它会给我一个运行时恐慌。
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.'
最小的示例代码片段如下所示:
use postgres::{Client, NoTls};
use my_crate::my_libs::fill_data_model_from_db;
#[macro_use] extern crate rocket;
#[get("/world")]
fn world() -> &'static str {
"Hello, world!"
}
#[launch]
fn rocket() -> _ {
let mut client: Client = Client::connect("host=localhost dbname=testdb", NoTls).unwrap();
// long running db queries for data preparation
// let d = fill_data_model_from_db(&mut client);
// will use State to encapsulate `d`
rocket::build().mount("/hello", routes![world])
}
我有点奇怪,虽然postgres::Client
实际上是一个synchronous PostgreSQL client
,正如它的文档所说,为什么创建它会导致嵌套的tokio运行时问题?我已经看过 rocket_db_pools,但无法弄清楚数据库池在这里有何帮助。我对 Rust 和 Rocket 还是很陌生。任何提示或帮助都将非常受欢迎!非常感谢!
postgres::Client
从调用者的角度来看是同步的,但它通过创建运行时并在内部调用异步 API 来工作。
在这种情况下,解决方案非常简单:只需将 rocket
函数设为 async
并使用异步 Postgres API:
use tokio_postgres::{Client, NoTls};
#[macro_use] extern crate rocket;
#[get("/world")]
fn world() -> &'static str {
"Hello, world!"
}
#[launch]
async fn rocket() -> _ {
let (client, connection) = tokio_postgres::connect("host=localhost dbname=testdb", NoTls).await.unwrap();
tokio::spawn(async move {
if let Err(e) = connection.await {
eprintln!("connection error: {}", e);
}
});
// use `client` to make asynchronous DB requests
rocket::build().mount("/hello", routes![world])
}