From 033b89ccb8a51a50ee24a2105cb668205e9d2886 Mon Sep 17 00:00:00 2001 From: xfy Date: Thu, 18 Jun 2026 11:18:36 +0800 Subject: [PATCH] perf(posts): offload Markdown rendering to spawn_blocking MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit create/update/rebuild 三处 Markdown 渲染(含 syntect 高亮)移到阻塞 线程池。rebuild 用 spawn_blocking 的 JoinError 替代 catch_unwind 捕获 渲染 panic,避免单条记录拖垮整批。 --- src/api/posts/create.rs | 9 +++++++-- src/api/posts/rebuild.rs | 12 ++++++++---- src/api/posts/update.rs | 9 +++++++-- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/src/api/posts/create.rs b/src/api/posts/create.rs index 55641ec..784040c 100644 --- a/src/api/posts/create.rs +++ b/src/api/posts/create.rs @@ -76,8 +76,13 @@ pub async fn create_post( { let mut client = get_conn().await.map_err(AppError::db_conn)?; - // 渲染 Markdown 为 HTML,并提取目录。 - let rendered = crate::api::markdown::render_markdown_enhanced(&content_md); + // Markdown 渲染(含 syntect 高亮)是 CPU 密集任务,移到阻塞线程池执行。 + let md_for_render = content_md.clone(); + let rendered = tokio::task::spawn_blocking(move || { + crate::api::markdown::render_markdown_enhanced(&md_for_render) + }) + .await + .map_err(|_| AppError::Internal("Markdown 渲染任务失败"))?; let content_html = rendered.html; let toc_html = if rendered.toc_html.is_empty() { None:: diff --git a/src/api/posts/rebuild.rs b/src/api/posts/rebuild.rs index b53d166..32fa801 100644 --- a/src/api/posts/rebuild.rs +++ b/src/api/posts/rebuild.rs @@ -55,10 +55,14 @@ pub async fn rebuild_content_html(rebuild_all: bool) -> Result r, Err(_) => { failed += 1; diff --git a/src/api/posts/update.rs b/src/api/posts/update.rs index f87a75e..bbb6867 100644 --- a/src/api/posts/update.rs +++ b/src/api/posts/update.rs @@ -40,8 +40,13 @@ pub async fn update_post( { let mut client = get_conn().await.map_err(AppError::db_conn)?; - // 重新渲染 Markdown 与目录。 - let rendered = crate::api::markdown::render_markdown_enhanced(&content_md); + // Markdown 渲染移到阻塞线程池执行。 + let md_for_render = content_md.clone(); + let rendered = tokio::task::spawn_blocking(move || { + crate::api::markdown::render_markdown_enhanced(&md_for_render) + }) + .await + .map_err(|_| AppError::Internal("Markdown 渲染任务失败"))?; let content_html = rendered.html; let toc_html = if rendered.toc_html.is_empty() { None::