codejump
MediumPro challengeJavaScriptTypeScript

Node.js — Respect Backpressure

Node.jsBackendStreamsBackpressure

tinyserve writes its access log through a stream. What happens when requests arrive faster than
the disk writes? stream.write() never refuses data: it buffers it in memory. Write in a tight
loop to a slow destination and the buffer grows until the process runs out of memory.

The protocol to avoid that is backpressure:
[`write()`](https://nodejs.org/api/stream.html#writablewritechunk-encoding-callback) returns
false once the buffer reaches the stream's highWaterMark, and the stream emits 'drain'
when it is worth writing again.

Your task

Write async writeAll(stream, lines):

1. Write each line followed by \n, in order.
2. Whenever write() returns false, wait for 'drain' before writing the next line.
3. Then call stream.end() and wait until the stream has finished (everything flushed).
4. If the stream fails ('error'), writeAll must reject with that error — not hang.

The driver's stream is a deliberately slow disk with a small highWaterMark. It records the
largest amount of data ever buffered, checks that everything arrived in order, and that the stream
finished before writeAll resolved. One test makes the disk fail midway with 'Disk full'.

Tools

  • [`events.once(emitter, name)`](https://nodejs.org/api/events.html#eventsonceemitter-name-options)

— a promise of the next event; it rejects if 'error' is emitted first.

  • [`finished(stream)`](https://nodejs.org/api/stream.html#streamfinishedstream-options) from

node:stream/promises — resolves when the stream is done, rejects on error.

Sample tests

Test #1Small write
Input: [["a","b","c"],1024,null]
Output: {"complete":true,"finished":true,"respectedBackpressure":true}
Test #2200 lines into a 64-byte buffer
Input: [["GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200","GET /index.html 200"],64,null]
Output: {"complete":true,"finished":true,"respectedBackpressure":true}
Test #3The disk fails midway
Input: [["ok-0","ok-1","ok-2","ok-3","ok-4","ok-5","ok-6","ok-7","ok-8","ok-9","ok-10","ok-11","ok-12","ok-13","ok-14","ok-15","ok-16","ok-17","ok-18","ok-19","POISON","ok-21","ok-22","ok-23","ok-24","ok-25","ok-26","ok-27","ok-28","ok-29","ok-30","ok-31","ok-32","ok-33","ok-34","ok-35","ok-36","ok-37","ok-38","ok-39","ok-40","ok-41","ok-42","ok-43","ok-44","ok-45","ok-46","ok-47","ok-48","ok-49"],32,"POISON"]
Output: {"error":"Disk full"}
Test #4Nothing to write
Input: [[],16,null]
Output: {"complete":true,"finished":true,"respectedBackpressure":true}