When handling concurrent async work (streaming, tees, semaphores/limits, watchdogs), ensure cancellation, timeouts, and accounting are tied to the actual consumer lifecycle—release/decrement/teardown at the point where the work is truly finished, and don’t block on cancellation promises that can’t resolve until another branch drains.
Practical rules:
TransformStream.flush/end-of-stream), not when headers/initial chunks arrive.undefined.Example pattern (release on flush, not header arrival):
const slot = await acquireSemaphore();
let released = false;
const releaseOnce = () => {
if (released) return;
released = true;
slot();
};
return new TransformStream<Uint8Array, Uint8Array>({
transform(chunk, controller) {
controller.enqueue(chunk);
},
flush() {
// stream fully consumed (client drained)
releaseOnce();
}
});
These practices reduce race conditions, deadlocks, leaked capacity, and spurious failures in highly concurrent streaming systems.
Enter the URL of a public GitHub repository