fix: cancel abandoned highlight() semantic work and harden WASM engine recovery
highlight() used Promise.race with a 10s timeout, but the losing semantic phase promise continued running 25 WASM micro-batches, saturating the event loop and degrading all subsequent operations (find() going from ~200ms to ~10,000ms). Add AbortController to highlight() so the semantic phase stops immediately on timeout or error. Pass abort signal through embedBatch() → EmbeddingManager → micro-batch loop. Also add defensive hardening: - CandleEmbeddingEngine: try/catch around WASM calls resets engine state on failure so next call triggers re-initialization - WASMEmbeddingEngine: initialize() now checks underlying Candle engine state, not just its own flag, completing the recovery chain
This commit is contained in:
parent
279fccebfe
commit
f8dd93c93c
4 changed files with 54 additions and 23 deletions
|
|
@ -205,19 +205,27 @@ export class CandleEmbeddingEngine {
|
|||
throw new Error('Engine not properly initialized')
|
||||
}
|
||||
|
||||
const startTime = Date.now()
|
||||
try {
|
||||
const startTime = Date.now()
|
||||
|
||||
const embedding = this.engine.embed(text)
|
||||
const embeddingArray = Array.from(embedding)
|
||||
const embedding = this.engine.embed(text)
|
||||
const embeddingArray = Array.from(embedding)
|
||||
|
||||
const processingTimeMs = Date.now() - startTime
|
||||
this.embedCount++
|
||||
this.totalProcessingTimeMs += processingTimeMs
|
||||
const processingTimeMs = Date.now() - startTime
|
||||
this.embedCount++
|
||||
this.totalProcessingTimeMs += processingTimeMs
|
||||
|
||||
return {
|
||||
embedding: embeddingArray,
|
||||
tokenCount: 0, // Candle handles tokenization internally
|
||||
processingTimeMs,
|
||||
return {
|
||||
embedding: embeddingArray,
|
||||
tokenCount: 0, // Candle handles tokenization internally
|
||||
processingTimeMs,
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('WASM embed failed, marking engine for re-initialization:', error)
|
||||
this.initialized = false
|
||||
this.engine = null
|
||||
this.wasmModule = null
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -237,10 +245,18 @@ export class CandleEmbeddingEngine {
|
|||
return []
|
||||
}
|
||||
|
||||
const embeddings = this.engine.embed_batch(texts)
|
||||
this.embedCount += texts.length
|
||||
try {
|
||||
const embeddings = this.engine.embed_batch(texts)
|
||||
this.embedCount += texts.length
|
||||
|
||||
return embeddings.map((e) => Array.from(e))
|
||||
return embeddings.map((e) => Array.from(e))
|
||||
} catch (error) {
|
||||
console.error('WASM embedBatch failed, marking engine for re-initialization:', error)
|
||||
this.initialized = false
|
||||
this.engine = null
|
||||
this.wasmModule = null
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -52,8 +52,9 @@ export class WASMEmbeddingEngine {
|
|||
* Initialize the engine
|
||||
*/
|
||||
async initialize(): Promise<void> {
|
||||
// Already initialized
|
||||
if (this.initialized) {
|
||||
// Only skip if BOTH this layer and the underlying Candle engine are initialized.
|
||||
// If Candle crashed and reset itself, we must re-initialize even though our flag is true.
|
||||
if (this.initialized && this.candleEngine.isInitialized()) {
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue