mirror of
https://github.com/moeru-ai/airi.git
synced 2026-08-14 00:48:06 +00:00
fix(stage-ui): preserve Kokoro worker on abort (#1911)
This commit is contained in:
@@ -170,6 +170,45 @@ describe('kokoro adapter - device loss resilience', () => {
|
||||
}))
|
||||
})
|
||||
|
||||
it('should not restart the worker when generation is aborted', async () => {
|
||||
const { createKokoroAdapter } = await import('./kokoro')
|
||||
const adapter = createKokoroAdapter()
|
||||
|
||||
const loading = adapter.loadModel('q4', 'webgpu')
|
||||
await vi.waitFor(() => expect(enqueueMock).toHaveBeenCalled())
|
||||
|
||||
const worker = MockWorker.instances.at(-1)!
|
||||
const loadRequest = worker.postMessage.mock.calls.find(([message]) => message.type === 'load-model')?.[0]
|
||||
expect(loadRequest?.requestId).toBeDefined()
|
||||
worker.dispatch('message', {
|
||||
data: {
|
||||
type: 'model-ready',
|
||||
requestId: loadRequest.requestId,
|
||||
device: 'webgpu',
|
||||
metadata: { voices: { af_heart: { name: 'Heart' } } },
|
||||
},
|
||||
})
|
||||
await loading
|
||||
expect(adapter.state).toBe('ready')
|
||||
|
||||
const controller = new AbortController()
|
||||
const generating = adapter.generate('hello', 'af_heart' as any, { signal: controller.signal })
|
||||
|
||||
await vi.waitFor(() => {
|
||||
expect(worker.postMessage).toHaveBeenCalledWith(expect.objectContaining({ type: 'run-inference' }))
|
||||
})
|
||||
|
||||
controller.abort('cancel speech')
|
||||
|
||||
await expect(generating).rejects.toMatchObject({ name: 'AbortError' })
|
||||
expect(adapter.state).toBe('ready')
|
||||
expect(worker.terminate).not.toHaveBeenCalled()
|
||||
expect(worker.postMessage).toHaveBeenCalledWith(expect.objectContaining({
|
||||
type: 'cancel',
|
||||
targetRequestId: expect.any(String),
|
||||
}))
|
||||
})
|
||||
|
||||
it('should classify worker device-loss errors before restarting', async () => {
|
||||
const { createKokoroAdapter } = await import('./kokoro')
|
||||
const adapter = createKokoroAdapter()
|
||||
|
||||
@@ -463,6 +463,15 @@ export function createKokoroAdapter(): KokoroAdapter {
|
||||
if (error === notReadyError)
|
||||
throw error
|
||||
|
||||
// Cancellation is a caller-controlled lifecycle outcome, not a worker
|
||||
// failure. Keep the loaded model available and avoid restarting the
|
||||
// worker after waitForWorkerMessage has already posted `cancel`.
|
||||
if ((error as Error)?.name === 'AbortError') {
|
||||
if (state === 'running')
|
||||
state = 'ready'
|
||||
throw error
|
||||
}
|
||||
|
||||
handleWorkerError(error instanceof Error ? error : new Error(String(error)))
|
||||
throw error
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user