fix: prevent WASM embedding from blocking event loop during highlight()
embedBatch() with large inputs (e.g. 500 chunks from highlight()) runs a single synchronous WASM forward pass that blocks the event loop for 200-500ms. Split large batches into micro-batches of 20 with setTimeout(0) yields between each, keeping max blocking per batch to ~10-30ms. Also change Cargo.toml opt-level from "z" (size) to 3 (speed) for ~15-20% faster WASM inference. Requires WASM rebuild to take effect.
This commit is contained in:
parent
1ffdfa70ae
commit
bf71317d21
2 changed files with 30 additions and 4 deletions
|
|
@ -212,6 +212,10 @@ export class EmbeddingManager {
|
|||
* Uses the engine's embedBatch() for a single WASM forward pass
|
||||
* instead of N individual embed() calls.
|
||||
*
|
||||
* Large batches (>MICRO_BATCH_SIZE) are split into micro-batches
|
||||
* with event loop yielding between each, preventing the synchronous
|
||||
* WASM call from blocking the server for hundreds of milliseconds.
|
||||
*
|
||||
* @param texts Array of strings to embed
|
||||
* @returns Array of embedding vectors (384 dimensions each)
|
||||
*/
|
||||
|
|
@ -230,9 +234,31 @@ export class EmbeddingManager {
|
|||
}
|
||||
|
||||
await this.init()
|
||||
const results = await this.engine.embedBatch(texts)
|
||||
this.embedCount += texts.length
|
||||
return results
|
||||
|
||||
// Small batches: single WASM call (no overhead)
|
||||
const MICRO_BATCH_SIZE = 20
|
||||
if (texts.length <= MICRO_BATCH_SIZE) {
|
||||
const results = await this.engine.embedBatch(texts)
|
||||
this.embedCount += texts.length
|
||||
return results
|
||||
}
|
||||
|
||||
// Large batches: micro-batch with event loop yielding
|
||||
// Each micro-batch of ~20 texts blocks ~10-30ms, then yields
|
||||
// so other requests (HTTP, timers, I/O) can proceed
|
||||
const allResults: number[][] = []
|
||||
for (let i = 0; i < texts.length; i += MICRO_BATCH_SIZE) {
|
||||
const batch = texts.slice(i, i + MICRO_BATCH_SIZE)
|
||||
const batchResults = await this.engine.embedBatch(batch)
|
||||
allResults.push(...batchResults)
|
||||
this.embedCount += batch.length
|
||||
|
||||
// Yield to event loop between micro-batches
|
||||
if (i + MICRO_BATCH_SIZE < texts.length) {
|
||||
await new Promise<void>(resolve => setTimeout(resolve, 0))
|
||||
}
|
||||
}
|
||||
return allResults
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ getrandom = { version = "0.3", features = ["wasm_js"] }
|
|||
wasm-bindgen-test = "0.3"
|
||||
|
||||
[profile.release]
|
||||
opt-level = "z" # Optimize for size
|
||||
opt-level = 3 # Optimize for speed (~15-20% faster inference, ~1MB larger binary)
|
||||
lto = true # Link-time optimization
|
||||
codegen-units = 1 # Single codegen unit for better optimization
|
||||
panic = "abort" # Abort on panic (smaller binary)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue