我有一个应用程序写在金牛座(一个独立的应用程序)和火箭(web版本)。
应用程序使用一个大的(-ish)文件,保存在内存中(基本上是一个内存数据库),加载时间在1-10秒之间,但我不希望应用程序在打开前阻塞这段时间。
我的代码(火箭部分)目前看起来像这样:
#[rocket::get("/api/search?<searchTerm>&<take>&<skip>")]
pub fn search<'a>(
searchTerm: &str,
take: Option<u32>,
skip: Option<u32>,
db: &rocket::State<Database>
) -> Json<SearchResult>
{
Json(db.search(searchTerm, take, skip))
}
#[rocket::launch]
fn rocket() {
// ...
let db = Database::load().expect("Failed loading database");
rocket::build()
.mount("/", rocket::routes![search])
.manage(db);
}
我怎么能运行数据库::load()异步,不阻止启动火箭服务器/金牛应用程序,仍然能够得到它在search
?
我最终使用全局状态和RwLock,像这样:
static DB: RwLock::<Option<Database>> = RwLock::<Option<Database>>::new(None);
#[rocket::get("/api/search?<searchTerm>&<take>&<skip>")]
pub fn search<'a>(
searchTerm: &str,
take: Option<u32>,
skip: Option<u32>,
db: &rocket::State<Database>
) -> Json<SearchResult>
{
if let Some(db) = DB.read().expect("Cannot read the database because it failed to load.").as_ref() {
Json(jdict_shared::shared_api::search(db, searchTerm, take, skip))
}
else {
// TODO: return proper error code
Json(jdict_shared::shared_api::SearchResult::default())
}
}
#[rocket::launch]
fn rocket() {
// ...
std::thread::spawn(|| {
*DB.write().unwrap() = Some(Database::load(cfg.jdict));
});
rocket::build().mount("/", rocket::routes![search]);
}
这个可以工作,但是在我看来是一个非常丑陋的解决方案。