小红书导出三条读写命令挪到阻塞线程池

- commands 新增 offload:用 tokio::task::spawn_blocking 包住同步文件 IO
- read / readHash / save 三条命令改走 offload,JoinError 收口成 ExportUnavailable
This commit is contained in:
2026-10-06 19:23:36 +08:00
parent 158fae5879
commit 63b7ef3665
@@ -31,7 +31,11 @@ use super::{build, script};
pub(crate) async fn read_xhs_minitool_export(
project_path: String,
) -> Result<XHSMiniToolExportState, XHSMiniToolExportReadError> {
let result = read_content(&project_path);
let result = offload({
let project_path = project_path.clone();
move || read_content(&project_path)
})
.await;
report("read", &project_path, &result);
result
}
@@ -43,7 +47,11 @@ pub(crate) async fn read_xhs_minitool_export(
pub(crate) async fn read_xhs_minitool_export_hash(
project_path: String,
) -> Result<String, XHSMiniToolExportReadError> {
let result = read_content_hash(&project_path);
let result = offload({
let project_path = project_path.clone();
move || read_content_hash(&project_path)
})
.await;
report("readHash", &project_path, &result);
result
}
@@ -58,7 +66,13 @@ pub(crate) async fn save_xhs_minitool_export_form(
form: XHSMiniToolExportForm,
base_hash: String,
) -> Result<String, XHSMiniToolExportSaveError> {
let result = save_form(&project_path, &form, &base_hash);
let result = offload({
let project_path = project_path.clone();
let form = form.clone();
let base_hash = base_hash.clone();
move || save_form(&project_path, &form, &base_hash)
})
.await;
report("save", &project_path, &result);
if let Ok(hash) = &result {
app_log!(
@@ -109,6 +123,25 @@ fn project_root(project_path: &str) -> Result<PathBuf, ExportUnavailable> {
Ok(root)
}
/// 把小块同步 IO 挪到 Tokio 的阻塞线程池。
///
/// 读命令每 2 秒被轮询一次,注册表 + `package.json` 探测虽然小,但直接在 `async fn` 里做同步
/// 文件 IO 会占着 worker 线程,拖慢同一 runtime 上的其它异步任务(构建子进程、SpacetimeDB
/// 客户端)。任务 panic 时 `JoinError` 收口成 `ExportUnavailable`,走各命令既有的失败表。
async fn offload<T, E, F>(job: F) -> Result<T, E>
where
T: Send + 'static,
E: From<ExportUnavailable> + Send + 'static,
F: FnOnce() -> Result<T, E> + Send + 'static,
{
match tokio::task::spawn_blocking(job).await {
Ok(result) => result,
Err(error) => Err(E::from(ExportUnavailable::new(format!(
"后台执行导出读写任务失败:{error}"
)))),
}
}
fn read_content(project_path: &str) -> Result<XHSMiniToolExportState, XHSMiniToolExportReadError> {
let root = project_root(project_path)?;
Ok(content(