Skip to content

Commit 9192aad

Browse files
committed
use spawn_blocking for cpu intensive template rendering
1 parent 0eb570d commit 9192aad

File tree

2 files changed

+53
-7
lines changed

2 files changed

+53
-7
lines changed

src/web/crate_details.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,7 @@ struct CrateDetailsPage {
302302

303303
impl_axum_webpage! {
304304
CrateDetailsPage = "crate/details.html",
305+
cpu_intensive_rendering = true,
305306
}
306307

307308
#[derive(Deserialize, Clone, Debug)]

src/web/page/web_page.rs

Lines changed: 52 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ use iron::{
1919
};
2020
use serde::Serialize;
2121
use std::{borrow::Cow, sync::Arc};
22-
use tera::{Context, Tera};
22+
use tera::Context;
23+
use tokio::task::spawn_blocking;
2324

2425
/// When making using a custom status, use a closure that coerces to a `fn(&Self) -> Status`
2526
#[macro_export]
@@ -61,11 +62,28 @@ macro_rules! impl_webpage {
6162

6263
#[macro_export]
6364
macro_rules! impl_axum_webpage {
64-
($page:ty = $template:literal $(, status = $status:expr)? $(, content_type = $content_type:expr)? $(,)?) => {
65-
$crate::impl_axum_webpage!($page = |_| ::std::borrow::Cow::Borrowed($template) $(, status = $status)? $(, content_type = $content_type)?);
65+
(
66+
$page:ty = $template:literal
67+
$(, status = $status:expr)?
68+
$(, content_type = $content_type:expr)?
69+
$(, cpu_intensive_rendering = $cpu_intensive_rendering:expr)?
70+
$(,)?
71+
) => {
72+
$crate::impl_axum_webpage!(
73+
$page = |_| ::std::borrow::Cow::Borrowed($template)
74+
$(, status = $status)?
75+
$(, content_type = $content_type)?
76+
$(, cpu_intensive_rendering = $cpu_intensive_rendering )?
77+
);
6678
};
6779

68-
($page:ty = $template:expr $(, status = $status:expr)? $(, content_type = $content_type:expr)? $(,)?) => {
80+
(
81+
$page:ty = $template:expr
82+
$(, status = $status:expr)?
83+
$(, content_type = $content_type:expr)?
84+
$(, cpu_intensive_rendering = $cpu_intensive_rendering:expr)?
85+
$(,)?
86+
) => {
6987
impl axum::response::IntoResponse for $page
7088
{
7189
fn into_response(self) -> ::axum::response::Response {
@@ -76,6 +94,12 @@ macro_rules! impl_axum_webpage {
7694
ct = $content_type;
7795
)?
7896

97+
#[allow(unused_mut, unused_assignments)]
98+
let mut cpu_intensive_rendering = false;
99+
$(
100+
cpu_intensive_rendering = $cpu_intensive_rendering;
101+
)?
102+
79103
let mut response = ::axum::http::Response::builder()
80104
.header(::axum::http::header::CONTENT_TYPE, ct)
81105
$(
@@ -96,6 +120,7 @@ macro_rules! impl_axum_webpage {
96120
let template: fn(&Self) -> ::std::borrow::Cow<'static, str> = $template;
97121
template(&self).to_string()
98122
},
123+
cpu_intensive_rendering,
99124
});
100125
response
101126
}
@@ -189,14 +214,20 @@ pub trait WebPage: Serialize + Sized {
189214
pub(crate) struct DelayedTemplateRender {
190215
pub template: String,
191216
pub context: Context,
217+
pub cpu_intensive_rendering: bool,
192218
}
193219

194-
fn render_response(mut response: AxumResponse, templates: &Tera, csp_nonce: &str) -> AxumResponse {
220+
fn render_response(
221+
mut response: AxumResponse,
222+
templates: Arc<TemplateData>,
223+
csp_nonce: String,
224+
) -> AxumResponse {
195225
if let Some(render) = response.extensions().get::<DelayedTemplateRender>() {
226+
let tera = &templates.templates;
196227
let mut context = render.context.clone();
197228
context.insert("csp_nonce", &csp_nonce);
198229

199-
let rendered = match templates.render(&render.template, &context) {
230+
let rendered = match tera.render(&render.template, &context) {
200231
Ok(content) => content,
201232
Err(err) => {
202233
if response.status().is_server_error() {
@@ -239,5 +270,19 @@ pub(crate) async fn render_templates_middleware<B>(
239270
.nonce()
240271
.to_owned();
241272

242-
render_response(next.run(req).await, &templates.templates, &csp_nonce)
273+
let response = next.run(req).await;
274+
275+
let cpu_intensive_rendering: bool = response
276+
.extensions()
277+
.get::<DelayedTemplateRender>()
278+
.map(|render| render.cpu_intensive_rendering)
279+
.unwrap_or(false);
280+
281+
if cpu_intensive_rendering {
282+
spawn_blocking(|| render_response(response, templates, csp_nonce))
283+
.await
284+
.expect("tokio task join error when rendering templates")
285+
} else {
286+
render_response(response, templates, csp_nonce)
287+
}
243288
}

0 commit comments

Comments
 (0)