64 lines
1.8 KiB
TypeScript
64 lines
1.8 KiB
TypeScript
/** @jest-environment node */
|
||
|
||
describe('image-processing-limiter', () => {
|
||
afterEach(() => {
|
||
delete process.env.IMAGE_PROCESSING_MAX_CONCURRENT
|
||
})
|
||
|
||
test('并发为 2 时同时释放两个任务,名额仍先直接转交给既有等待者', async () => {
|
||
jest.resetModules()
|
||
process.env.IMAGE_PROCESSING_MAX_CONCURRENT = '2'
|
||
const { withImageProcessingSlot } = await import('@/lib/image-processing-limiter')
|
||
|
||
const releases: Array<() => void> = []
|
||
const started: number[] = []
|
||
let active = 0
|
||
let peak = 0
|
||
|
||
const runTask = (index: number) => withImageProcessingSlot(() => {
|
||
active += 1
|
||
peak = Math.max(peak, active)
|
||
started.push(index)
|
||
return new Promise<void>((resolve) => {
|
||
releases[index] = () => {
|
||
active -= 1
|
||
resolve()
|
||
}
|
||
})
|
||
})
|
||
|
||
const firstTask = runTask(0)
|
||
const secondTask = runTask(1)
|
||
const firstQueuedTask = runTask(2)
|
||
const secondQueuedTask = runTask(3)
|
||
|
||
await new Promise<void>((resolve) => setImmediate(resolve))
|
||
expect(started).toEqual([0, 1])
|
||
|
||
releases[0]()
|
||
releases[1]()
|
||
// 两个 release continuation 已排入微任务后再发起新请求。旧实现会先把
|
||
// active 降到 0,新请求 4 因而抢入,随后等待者 2、3 继续自增到 3。
|
||
const lateTask = Promise.resolve().then(() => runTask(4))
|
||
await new Promise<void>((resolve) => setImmediate(resolve))
|
||
expect(started).toEqual([0, 1, 2, 3])
|
||
expect(peak).toBe(2)
|
||
|
||
releases[2]()
|
||
releases[3]()
|
||
await new Promise<void>((resolve) => setImmediate(resolve))
|
||
expect(started).toEqual([0, 1, 2, 3, 4])
|
||
|
||
releases[4]()
|
||
await Promise.all([
|
||
firstTask,
|
||
secondTask,
|
||
firstQueuedTask,
|
||
secondQueuedTask,
|
||
lateTask,
|
||
])
|
||
expect(peak).toBe(2)
|
||
|
||
})
|
||
})
|