fix: free runtime call queue after sync throw

This commit is contained in:
Neil
2026-05-30 09:24:36 -07:00
parent d4f00e3748
commit fd0170dc0c
2 changed files with 16 additions and 2 deletions
+12
View File
@@ -37,4 +37,16 @@ describe('runtime RPC call queue', () => {
pending.shift()?.('background-2')
await expect(background2).resolves.toBe('background-2')
})
it('frees the queue slot when a runtime call throws synchronously', async () => {
const queue = new RuntimeRpcCallQueuePool(1, 1)
const first = queue.enqueue('web-runtime', 'status.get', () => {
throw new Error('invalid stored runtime pairing')
})
await expect(first).rejects.toThrow('invalid stored runtime pairing')
const second = queue.enqueue('web-runtime', 'status.get', async () => 'second')
await expect(second).resolves.toBe('second')
})
})
+4 -2
View File
@@ -77,8 +77,10 @@ export class RuntimeRpcCallQueuePool {
}
// Why: runtime streams and worktree actions share transport capacity with
// per-card status refreshes, so decorative calls must not stampede it.
void call
.run()
// Invoke through the promise chain so sync validation errors free the
// queue slot just like async transport failures.
void Promise.resolve()
.then(call.run)
.then(call.resolve, call.reject)
.finally(() => {
queue.active = Math.max(0, queue.active - 1)