mirror of
https://github.com/stablyai/orca.git
synced 2026-09-23 08:02:31 +00:00
* perf(runtime): remove timer clamps from cooperative yields Renderer paste and input loops can schedule more than a thousand zero-delay timer yields for a maximum-size payload. Chromium clamps nested timers to 4ms, adding seconds of idle wall time. Use MessageChannel tasks in renderer runtimes and setImmediate in Node while retaining a timer fallback for tests and unsupported environments. * fix(runtime): preserve pacing and release yield callbacks Adversarial review found that concurrent producers could retain resolved callbacks until global quiescence. Route renderer yields by token and delete each resolver before resuming its producer. Keep timer pacing in terminal paste and accepted-write loops where SSH and local PTYs do not provide drain acknowledgement. Use the shared scheduler for the OpenCode scanner.
55 lines
1.7 KiB
TypeScript
55 lines
1.7 KiB
TypeScript
import { afterEach, describe, expect, it, vi } from 'vitest'
|
|
import { getPendingRendererYieldCountForTesting, yieldToEventLoop } from './event-loop-yield'
|
|
|
|
afterEach(() => {
|
|
vi.unstubAllEnvs()
|
|
vi.unstubAllGlobals()
|
|
})
|
|
|
|
describe('yieldToEventLoop', () => {
|
|
it('uses setImmediate in Node runtimes', async () => {
|
|
const scheduleImmediate = vi.fn((callback: () => void) => queueMicrotask(callback))
|
|
vi.stubEnv('VITEST', 'false')
|
|
vi.stubGlobal('window', undefined)
|
|
vi.stubGlobal('setImmediate', scheduleImmediate)
|
|
|
|
await yieldToEventLoop()
|
|
|
|
expect(scheduleImmediate).toHaveBeenCalledOnce()
|
|
})
|
|
|
|
it('releases callbacks during sustained concurrent renderer yields', async () => {
|
|
const postMessage = vi.fn()
|
|
let peakPendingAfterResolution = 0
|
|
vi.stubEnv('VITEST', 'false')
|
|
vi.stubGlobal('window', {})
|
|
vi.stubGlobal(
|
|
'MessageChannel',
|
|
class {
|
|
port1: { onmessage: ((event: MessageEvent) => void) | null } = { onmessage: null }
|
|
port2 = {
|
|
postMessage: (data: unknown): void => {
|
|
postMessage(data)
|
|
setTimeout(() => this.port1.onmessage?.({ data } as MessageEvent), 0)
|
|
}
|
|
}
|
|
}
|
|
)
|
|
|
|
const runProducer = async (): Promise<void> => {
|
|
for (let index = 0; index < 20; index += 1) {
|
|
await yieldToEventLoop()
|
|
peakPendingAfterResolution = Math.max(
|
|
peakPendingAfterResolution,
|
|
getPendingRendererYieldCountForTesting()
|
|
)
|
|
}
|
|
}
|
|
await Promise.all([runProducer(), runProducer()])
|
|
|
|
expect(postMessage).toHaveBeenCalledTimes(40)
|
|
expect(peakPendingAfterResolution).toBeLessThanOrEqual(1)
|
|
expect(getPendingRendererYieldCountForTesting()).toBe(0)
|
|
})
|
|
})
|