|
5 | 5 | //! - wasm only: direct type alias to WasmWorker (zero overhead) |
6 | 6 | //! - both: enum with runtime dispatch based on CodeType |
7 | 7 |
|
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; |
9 | 13 |
|
10 | 14 | use crate::ops::RunnerOperations; |
11 | 15 | use crate::store::{CodeType, WorkerWithBindings, bindings_to_infos}; |
12 | 16 |
|
| 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 | + |
13 | 29 | #[cfg(all(feature = "v8", feature = "wasm"))] |
14 | 30 | use openworkers_core::Task; |
15 | 31 |
|
@@ -97,20 +113,49 @@ pub async fn create_worker( |
97 | 113 | // Script preparation (shared across all configurations) |
98 | 114 | // ============================================================================= |
99 | 115 |
|
100 | | -/// Parse worker code based on code type |
| 116 | +/// Parse worker code based on code type (with caching for JS/TS) |
101 | 117 | fn parse_code(data: &WorkerWithBindings) -> Result<WorkerCode, TerminationReason> { |
102 | 118 | match data.code_type { |
103 | 119 | CodeType::Javascript | CodeType::Typescript => { |
104 | 120 | #[cfg(feature = "v8")] |
105 | 121 | { |
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) |
108 | 146 | .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)) |
114 | 159 | } |
115 | 160 |
|
116 | 161 | #[cfg(not(feature = "v8"))] |
|
0 commit comments