Skip to content

Commit 3e6eb98

Browse files
committed
fix(rolldown): avoid duplicate concurrent log reads
1 parent ba1672f commit 3e6eb98

2 files changed

Lines changed: 52 additions & 0 deletions

File tree

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import type { Event } from '@rolldown/debug'
2+
import { describe, expect, it, vi } from 'vitest'
3+
import { RolldownEventsReader } from '../events-reader'
4+
5+
describe('rolldown events reader', () => {
6+
it('does not process the same log bytes twice during concurrent reads', async () => {
7+
const reader = RolldownEventsReader.get('/mock/logs.json')
8+
let resolveRead!: () => void
9+
const readComplete = new Promise<void>((resolve) => {
10+
resolveRead = resolve
11+
})
12+
const event = { action: 'BuildStart', timestamp: '1772529438599', session_id: '5173' } satisfies Event
13+
14+
const readChanges = vi.fn(async () => {
15+
reader.manager.handleEvent(event)
16+
await readComplete
17+
})
18+
Object.defineProperty(reader, 'readChanges', { value: readChanges })
19+
20+
try {
21+
const reads = [
22+
reader.read(),
23+
reader.read(),
24+
reader.read(),
25+
]
26+
27+
expect(readChanges).toHaveBeenCalledTimes(1)
28+
resolveRead()
29+
await Promise.all(reads)
30+
31+
expect(reader.manager.events).toHaveLength(1)
32+
33+
await reader.read()
34+
expect(readChanges).toHaveBeenCalledTimes(2)
35+
}
36+
finally {
37+
reader.dispose()
38+
}
39+
})
40+
})

packages/rolldown/src/node/rolldown/events-reader.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ export class RolldownEventsReader {
1010
lastTimestamp: number = 0
1111
manager = new RolldownEventsManager()
1212
meta: SessionMeta | undefined
13+
private pendingRead: Promise<void> | undefined
1314

1415
private constructor(
1516
readonly filepath: string,
@@ -26,6 +27,17 @@ export class RolldownEventsReader {
2627
}
2728

2829
async read() {
30+
if (this.pendingRead) {
31+
return this.pendingRead
32+
}
33+
34+
this.pendingRead = this.readChanges().finally(() => {
35+
this.pendingRead = undefined
36+
})
37+
return this.pendingRead
38+
}
39+
40+
private async readChanges() {
2941
const { mtime, size } = await fs.promises.stat(this.filepath)
3042
if (mtime.getTime() <= this.lastTimestamp) {
3143
return

0 commit comments

Comments
 (0)