Skip to content

Commit 3803f3a

Browse files
committed
Use moka to cache rendered html in middleware::ember_html::serve_html
1 parent dd9e698 commit 3803f3a

File tree

5 files changed

+209
-25
lines changed

5 files changed

+209
-25
lines changed

Cargo.lock

Lines changed: 165 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ krata-tokio-tar = "=0.4.2"
9494
lettre = { version = "=0.11.11", default-features = false, features = ["file-transport", "smtp-transport", "hostname", "builder", "tokio1", "tokio1-native-tls"] }
9595
minijinja = { version = "=2.6.0", features = ["loader"] }
9696
mockall = "=0.13.1"
97+
moka = { version = "=0.12.10", default-features = false, features = ["future"] }
9798
native-tls = "=0.2.13"
9899
oauth2 = "=5.0.0"
99100
object_store = { version = "=0.11.2", features = ["aws"] }

src/config/server.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,11 @@ pub struct Server {
8484
/// [`Self::index_html_template_path`] is set.
8585
pub og_image_base_url: Option<Url>,
8686

87+
/// Maximum number of items that the HTML render
88+
/// cache in [`crate::middleware::ember_html::serve_html`]
89+
/// can hold. Defaults to 1024.
90+
pub html_render_cache_max_capacity: u64,
91+
8792
pub content_security_policy: Option<HeaderValue>,
8893
}
8994

@@ -234,6 +239,7 @@ impl Server {
234239
serve_dist: true,
235240
index_html_template_path,
236241
og_image_base_url,
242+
html_render_cache_max_capacity: var_parsed("HTML_RENDER_CACHE_CAP")?.unwrap_or(1024),
237243
content_security_policy: Some(content_security_policy.parse()?),
238244
})
239245
}

src/middleware/ember_html.rs

Lines changed: 36 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ const INDEX_TEMPLATE_NAME: &str = "index_html";
2626
const PATH_PREFIX_CRATES: &str = "/crates/";
2727

2828
type TemplateEnvFut = Shared<BoxFuture<'static, minijinja::Environment<'static>>>;
29+
type TemplateCache = moka::future::Cache<Cow<'static, str>, String>;
2930

3031
/// Initialize [`minijinja::Environment`] given the path to the index.html file. This should
3132
/// only be done once as it will load said file from persistent storage.
@@ -42,8 +43,16 @@ async fn init_template_env(
4243
env
4344
}
4445

46+
/// Initialize the [`moka::future::Cache`] used to cache the rendered HTML.
47+
fn init_html_cache(max_capacity: u64) -> TemplateCache {
48+
moka::future::CacheBuilder::new(max_capacity)
49+
.name("rendered_index_html")
50+
.build()
51+
}
52+
4553
pub async fn serve_html(state: AppState, request: Request, next: Next) -> Response {
4654
static TEMPLATE_ENV: OnceLock<TemplateEnvFut> = OnceLock::new();
55+
static RENDERED_HTML_CACHE: OnceLock<TemplateCache> = OnceLock::new();
4756

4857
let path = &request.uri().path();
4958
// The "/git/" prefix is only used in development (when within a docker container)
@@ -64,8 +73,7 @@ pub async fn serve_html(state: AppState, request: Request, next: Next) -> Respon
6473
// Come up with an Open Graph image URL. In case a crate page is requested,
6574
// we use the crate's name and the OG image base URL from config to
6675
// generate one, otherwise we use the fallback image.
67-
68-
let og_image_url: Cow<'_, _> = 'og: {
76+
let og_image_url = 'og: {
6977
if let Some(suffix) = path.strip_prefix(PATH_PREFIX_CRATES) {
7078
let len = suffix.find('/').unwrap_or(suffix.len());
7179
let krate = &suffix[..len];
@@ -81,26 +89,32 @@ pub async fn serve_html(state: AppState, request: Request, next: Next) -> Respon
8189
OG_IMAGE_FALLBACK_URL.into()
8290
};
8391

84-
// `OnceLock::get_or_init` blocks as long as its intializer is running in another thread.
85-
// Note that this won't take long, as the constructed Futures are not awaited
86-
// during initialization.
87-
let template_env = TEMPLATE_ENV.get_or_init(|| {
88-
// At this point we can safely assume `state.config.index_html_template_path` is `Some`,
89-
// as this middleware won't be executed otherwise; see `crate::middleware::apply_axum_middleware`.
90-
init_template_env(state.config.index_html_template_path.clone().unwrap())
91-
.boxed()
92-
.shared()
93-
});
94-
95-
// TODO use moka caching here with og_image_url as key and the rendered html as value
96-
97-
// Render the HTML given the OG image URL
98-
let env = template_env.clone().await;
99-
let html = env
100-
.get_template(INDEX_TEMPLATE_NAME)
101-
.unwrap()
102-
.render(context! { og_image_url})
103-
.expect("Error rendering index");
92+
// Fetch the HTML from cache given `og_image_url` as key or render it
93+
let html = RENDERED_HTML_CACHE
94+
.get_or_init(|| init_html_cache(state.config.html_render_cache_max_capacity))
95+
.get_with_by_ref(&og_image_url, async {
96+
// `OnceLock::get_or_init` blocks as long as its intializer is running in another thread.
97+
// Note that this won't take long, as the constructed Futures are not awaited
98+
// during initialization.
99+
let template_env = TEMPLATE_ENV.get_or_init(|| {
100+
// At this point we can safely assume `state.config.index_html_template_path` is `Some`,
101+
// as this middleware won't be executed otherwise; see `crate::middleware::apply_axum_middleware`.
102+
init_template_env(state.config.index_html_template_path.clone().unwrap())
103+
.boxed()
104+
.shared()
105+
});
106+
107+
// Render the HTML given the OG image URL
108+
let env = template_env.clone().await;
109+
let html = env
110+
.get_template(INDEX_TEMPLATE_NAME)
111+
.unwrap()
112+
.render(context! { og_image_url})
113+
.expect("Error rendering index");
114+
115+
html
116+
})
117+
.await;
104118

105119
// Serve static Ember page to bootstrap the frontend
106120
Response::builder()

src/tests/util/test_app.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -483,6 +483,7 @@ fn simple_config() -> config::Server {
483483
serve_dist: false,
484484
index_html_template_path: None,
485485
og_image_base_url: None,
486+
html_render_cache_max_capacity: 1024,
486487
content_security_policy: None,
487488
}
488489
}

0 commit comments

Comments
 (0)