Repository navigation
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## perf/stream-worker #1238 +/- ##
======================================================
+ Coverage 94.18% 94.33% +0.15%
======================================================
Files 291 293 +2
Lines 29214 30112 +898
Branches 2969 3060 +91
======================================================
+ Hits 27515 28406 +891
- Misses 1677 1684 +7
Partials 22 22 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
🚀 Deploying Preview to Cloudflare 🚀Preview Deployments by commit
|
dc17197 to
557f319
Compare
kgeminicdev
left a comment
There was a problem hiding this comment.
Read through createReplay and the cache changes. The check-then-wait in readFrom is race-free since nothing can push between the chunks.length check and recorded.wait(), forget() at release time is safe because the reader is registered in read() rather than on first next(), and an early break cleans up through the finally.
One edge: a reader from read() that's never iterated stays in readers at index 0. .return() on an unstarted async generator skips the body, so the finally never runs. A streamsInput generator that throws during setup or returns without touching its input would then pin every chunk until recording ends, for all the other readers too. Probably fine in practice, since a failure takes the run down anyway, but worth either a line in the streamsInput docs ("iterate the input or break out of it") or a test that pins down the behavior.
557f319 to
449050c
Compare
449050c to
d43c259
Compare
Every dependency edge was a full barrier: the cache collected all of a generator's chunks before its dependents started, so each stage of a build waited for the whole of the one before it. A generator can now set streamsInput: true to receive its dependency's output as an async iterable of chunks, read as they are produced. With one thread nothing runs alongside, so it still gets one array, and a dependency that doesn't stream arrives as a single chunk. Nothing sets it yet. The cache runs a streamed generator once, recording its chunks so any number of readers each read all of them, from the first, while it still runs. Once every reader has started, it lets go of a chunk as soon as all of them have read it, rather than holding the output until the last one is done. Assisted-by: Claude Opus 5.5 <noreply@anthropic.com> Assisted-by: Claude Sonnet 5.5 <noreply@anthropic.com>
worker.stream no longer waits on a signal, so createSignal comes with the replay, which wakes its readers with it as chunks are recorded. Assisted-by: Claude Opus 5.5 <noreply@anthropic.com>
d43c259 to
3ff6f70
Compare
Description
This PR lets the cache stream a generator's output to the generators that read it, instead of collecting every chunk first. It's the second part of a stack that splits #1205.
Every dependency edge was a full barrier:
cache.consumecollected all of a generator's chunks before its dependent started, so each stage of a build waited for the whole of the one before it.streamsInput: trueto get its dependency's output as an async iterable of chunks, read as they're produced. With one thread nothing runs alongside, so it still gets one array, and a dependency that doesn't stream arrives as a single chunk. No generator sets it yet.createReplay: any number of readers each read all of its chunks, from the first, while it still runs. Once every reader has started, a chunk is let go as soon as all of them have read it, rather than when the last one is done. Its readers wait oncreateSignal, a wake-up notified as each chunk is recorded and at the end.docs/creating-generators.mdhas a new Streaming Input section.Validation
Added tests for
createReplay(every reader gets every chunk in order, a reader that starts late, a chunk let go before a reader read it, a failure), for the cache (one run for streaming and collecting readers, chunks let go only once every reader has read them, a stream read only once, failures before and after the stream is read), and forrunGenerators(streaming to a generator that streams its input, and giving it the whole input with one thread). Built on 12 of Node.js's API docs at 1 and 4 threads, the output is byte-identical tomain's.Related Issues
Refs: #1205
Check List
node --run testand all tests passed.node --run format:check&node --run lint.