Skip to content

Commit 4b76191

Browse files
committed
feat: add LRU cache for transpiled worker code
- Cache transpiled JS/TS code by (worker_id, version) key - Capacity: 1000 workers - Avoids ~7ms transpilation on every request - Version key ensures automatic invalidation on deploy - Also add Display impl for CodeType for better logging
1 parent cac29dc commit 4b76191

2 files changed

Lines changed: 69 additions & 11 deletions

File tree

src/store.rs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,18 @@ pub enum CodeType {
1616
Snapshot,
1717
}
1818

19+
impl std::fmt::Display for CodeType {
20+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
21+
let s = match self {
22+
CodeType::Javascript => "javascript",
23+
CodeType::Typescript => "typescript",
24+
CodeType::Wasm => "wasm",
25+
CodeType::Snapshot => "snapshot",
26+
};
27+
write!(f, "{}", s)
28+
}
29+
}
30+
1931
#[derive(Clone, Debug, PartialEq, sqlx::Type)]
2032
#[sqlx(type_name = "enum_binding_type", rename_all = "lowercase")]
2133
pub enum BindingType {
@@ -416,10 +428,11 @@ pub async fn get_worker_with_bindings(
416428
}
417429

418430
log::debug!(
419-
"worker found: id: {}, version: {}, bindings: {}",
431+
"worker found: id: {}, version: {}, bindings: {}, type: {}",
420432
basic.id,
421433
basic.version,
422-
bindings.len()
434+
bindings.len(),
435+
basic.code_type
423436
);
424437

425438
Some(WorkerWithBindings {

src/worker.rs

Lines changed: 54 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,27 @@
55
//! - wasm only: direct type alias to WasmWorker (zero overhead)
66
//! - both: enum with runtime dispatch based on CodeType
77
8-
use std::sync::Arc;
8+
use std::num::NonZeroUsize;
9+
use std::sync::{Arc, Mutex};
10+
11+
use lru::LruCache;
12+
use once_cell::sync::Lazy;
913

1014
use crate::ops::RunnerOperations;
1115
use crate::store::{CodeType, WorkerWithBindings, bindings_to_infos};
1216

17+
// =============================================================================
18+
// Transpiled code cache
19+
// =============================================================================
20+
21+
/// Cache key: (worker_id, version)
22+
type CacheKey = (String, i32);
23+
24+
/// LRU cache for transpiled JavaScript code
25+
/// Capacity: 1000 workers (transpiled code is relatively small)
26+
static TRANSPILE_CACHE: Lazy<Mutex<LruCache<CacheKey, String>>> =
27+
Lazy::new(|| Mutex::new(LruCache::new(NonZeroUsize::new(1000).unwrap())));
28+
1329
#[cfg(all(feature = "v8", feature = "wasm"))]
1430
use openworkers_core::Task;
1531

@@ -97,20 +113,49 @@ pub async fn create_worker(
97113
// Script preparation (shared across all configurations)
98114
// =============================================================================
99115

100-
/// Parse worker code based on code type
116+
/// Parse worker code based on code type (with caching for JS/TS)
101117
fn parse_code(data: &WorkerWithBindings) -> Result<WorkerCode, TerminationReason> {
102118
match data.code_type {
103119
CodeType::Javascript | CodeType::Typescript => {
104120
#[cfg(feature = "v8")]
105121
{
106-
crate::transform::parse_worker_code(&data.code, &data.code_type)
107-
.map(WorkerCode::js)
122+
let cache_key = (data.id.clone(), data.version);
123+
124+
// Try to get from cache first
125+
{
126+
let mut cache = TRANSPILE_CACHE.lock().unwrap();
127+
128+
if let Some(cached_code) = cache.get(&cache_key) {
129+
log::debug!(
130+
"transpile cache HIT: worker={}, version={}",
131+
data.id,
132+
data.version
133+
);
134+
return Ok(WorkerCode::js(cached_code.clone()));
135+
}
136+
}
137+
138+
log::debug!(
139+
"transpile cache MISS: worker={}, version={}",
140+
data.id,
141+
data.version
142+
);
143+
144+
// Transpile and cache
145+
let transpiled = crate::transform::parse_worker_code(&data.code, &data.code_type)
108146
.map_err(|e| {
109-
TerminationReason::InitializationError(format!(
110-
"Failed to parse worker code: {}",
111-
e
112-
))
113-
})
147+
TerminationReason::InitializationError(format!(
148+
"Failed to parse worker code: {}",
149+
e
150+
))
151+
})?;
152+
153+
{
154+
let mut cache = TRANSPILE_CACHE.lock().unwrap();
155+
cache.put(cache_key, transpiled.clone());
156+
}
157+
158+
Ok(WorkerCode::js(transpiled))
114159
}
115160

116161
#[cfg(not(feature = "v8"))]

0 commit comments

Comments
 (0)