由於本文當下 2024/05/01 在 Rocket Async Diesel 的 Library 底下還沒有支援從內部取得 Connection 的方法,若不想重新寫一個 Connection 當作 Wrap 的情況下,可以把記憶體直接裝到新的型別變數中。
強制轉型記憶體的方法 Unsafe
實際上在 Rocket 的範例中,要讓每個進入 Function 的 Router 同時接收 DbConn 參數,大多都是由 from_request [1] 這個地方從 "request: &'r rocket::Request<'_>" 這個方法裡面取的 DbConn,例如:
async fn from_request(
request: &'r rocket::Request<'_>,
) -> rocket::request::Outcome<Self, Self::Error> {
let mut db = request.guard::<DbConn>().await;
但是,除此之外,要不透過 http 的 API Router 打進來去執行取得共用的 DbConn 卻很困難,例如有外 Cronjob 或是其他 Threading 去控制背景工作。
以下是一個方法,透過 Rocket 啟動時的 on_ignite ,可以讓 MyDb 從 rocket 取得 context,但是由於缺少型標轉換,因此可以透過 unsafe { std::mem::transmute }} 的方法強制轉換到該變數中。
use rocket_db_pools::diesel::{
pooled_connection::{
deadpool::{self, Object},
AsyncDieselConnectionManager,
},
AsyncConnection, AsyncMysqlConnection, MysqlPool, Pool, SimpleAsyncConnection,
};
#[derive(Database)]
#[database("my_db")]
pub struct MyDb(MysqlPool);
pub type DbConn = Connection<MainDb>;
rocket::build()
.attach(MyDb::init())
.attach(AdHoc::on_ignite("Seeding database", |rocket| async move {
let db = MyDb::fetch(&rocket).unwrap();
// Object<AsyncDieselConnectionManager<AsyncMysqlConnection>>
let mut conn = db.get().await.unwrap();
let mut clone_conn = db.clone().get().await.unwrap();
let mut casted_conn: DbConn = unsafe { std::mem::transmute(clone_conn) };
// 此時 Diesel 上的操作可以從這裡開始做了
})重寫 Connection
或者,可以重新寫一個 Conncetion 讓 DbConn 的 Type 是自己 Wrap 上來的:
use rocket_db_pools::{Database, Pool};
pub struct Connection<D: Database>(<D::Pool as Pool>::Connection);
impl<D: Database> Connection<D> {
pub async fn get (db: &D) -> Self {
Connection(db.get().await.unwrap().into())
}
}
當這麼做以後,事實上 DbConn 接下來就可以直接使用 get 取得連線:
#[derive(Database)]
#[database("my_db")]
pub struct MyDb(MysqlPool);
pub type DbConn = Connection<MainDb>;
AdHoc::on_ignite("Init", |rocket| async move {
let db = MyDb::fetch(&rocket).expect("Failed");
let conn = DbConn::get(db).await.expect("Failed");
tokio::spawn(async move {
do_something(conn, tasks)
.await
.expect("Failed to run rescheduler");
});
rocket
})
Reference:
[1]: https://api.rocket.rs/v0.5/rocket/request/trait.FromRequest

沒有留言:
張貼留言