You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Backpressure is the mechanism by which a consumer signals to a producer that it should slow down. In this API, backpressure is managed through [=backpressure policies=]:
144
144
145
-
* **`"strict"`** (default): Catches producers that ignore backpressure. Properly awaited writes wait for buffer space; un-awaited writes exceeding the buffer limit cause a rejection. Both the slots buffer and pending writes queue are limited by `highWaterMark`.
145
+
* **`"strict"`** (default): Catches producers that ignore backpressure. Properly awaited asynchronous writes wait for buffer space; un-awaited writes exceeding the buffer limit cause a rejection. Both the slots buffer and pending writes queue are limited to `highWaterMark` entries. Synchronous writes (`writeSync`, `writevSync`) only attempt the slots buffer; if it is full, they return `false` without placing data into the pending writes queue.
146
146
147
-
* **`"block"`**: Async writes wait for buffer space. Sync writes return `false` when the buffer is full. The pending writes queue is unbounded.
147
+
* **`"block"`**: Asynchronous writes that cannot be placed in the slots buffer are placed into the pending writes queue, which is unbounded, and resolve when promoted to the slots buffer. Synchronous writes return `false` when the slots buffer is full — the data is not accepted. The caller should fall back to the asynchronous method, which handles the pending queue.
148
148
149
-
* **`"drop-oldest"`**: Oldest buffered data is discarded to make room for new data. Writes never block.
149
+
* **`"drop-oldest"`**: Oldest buffered data is discarded to make room for new data. Writes never block or wait.
150
150
151
-
* **`"drop-newest"`**: Incoming data is silently discarded when buffer is full. Writes never block.
151
+
* **`"drop-newest"`**: Incoming data is silently discarded when buffer is full. Writes never block or wait.
152
152
153
153
The `highWaterMark` option controls the buffer size in slots (chunk batches), not bytes. It is clamped to a minimum of 1. Implementations may also apply a reasonable upper limit; the specific maximum is implementation-defined, but must be at least 1024.
154
154
@@ -367,7 +367,7 @@ Like {{Writer}}, {{SyncWriter}} is an interface, not a concrete class. Implement
367
367
368
368
{{SyncWriter}} follows the same [=backpressure policies=] as {{Writer}} with adaptations for synchronous operation:
369
369
370
-
* With `"block"`, {{SyncWriter/writeSync()}} and {{SyncWriter/writevSync()}}always enqueue the chunk(s) and return `true` when the buffer has space, or enqueue and return `false` when the buffer is full. The `false` return is a backpressure signal; the data is still accepted, but the caller should slow down.
370
+
* With `"block"`, {{SyncWriter/writeSync()}} and {{SyncWriter/writevSync()}} enqueue the chunk(s) and return `true` when the buffer has space, or return `false` when the buffer is full. The data is not accepted; the caller should retry when capacity becomes available.
371
371
* With `"strict"`, writes that exceed the buffer capacity throw a {{RangeError}}.
372
372
* With `"drop-oldest"` and `"drop-newest"`, writes behave as described in [[#concept-backpressure]]: the oldest or newest data is discarded respectively. Writes never fail.
373
373
* {{SyncWriter/endSync()}} throws a {{TypeError}} if the writer is already closed or errored.
@@ -519,7 +519,7 @@ When called, it performs the following steps:
519
519
<li>Let |backpressure| be |options|["{{PushStreamOptions/backpressure}}"].
520
520
<li>Let |signal| be |options|["{{PushStreamOptions/signal}}"] if present; otherwise `undefined`.
521
521
<li>Create an internal slots buffer with capacity |highWaterMark|.
522
-
<li>Create a pending writes queue. If |backpressure| is `"strict"`, limit its capacity to |highWaterMark|.
522
+
<li>Create a pending writes queue. If |backpressure| is `"strict"`, limit its capacity to |highWaterMark|. The pending writes queue is used exclusively by the asynchronous write methods ({{Writer/write()}}, {{Writer/writev()}}); the synchronous methods ({{Writer/writeSync()}}, {{Writer/writevSync()}}) do not interact with it.
523
523
<li>Let |writer| be a new {{Writer}} backed by the internal buffer, the pending writes queue, the [=backpressure policy=] |backpressure|, and |signal| if present.
524
524
<li>Let |pipelineController| be a new {{AbortController}}. If |signal| is not `undefined`, set |pipelineController|'s signal to follow |signal|.
525
525
<li>Let |bufferIterable| be an async iterable that dequeues the next batch from the slots buffer on each step (waiting if empty).
@@ -538,6 +538,15 @@ The Writer interface {#writer-section}
538
538
539
539
A {{Writer}} provides the interface for producing data. Implementations of {{Writer}} are returned by {{Stream/push()}}, {{Stream/broadcast()}}, and {{Stream/duplex()}}, but any object conforming to this interface can serve as a writer.
540
540
541
+
A {{Writer}} backed by a [=push stream=] maintains two internal queues:
542
+
543
+
* The **slots buffer**: a bounded queue of batches ready for the consumer to read. Its capacity is `highWaterMark` entries.
544
+
* The **pending writes queue**: a queue of writes waiting for space in the slots buffer. Under `"strict"`, its capacity is also `highWaterMark` entries. Under `"block"`, it is unbounded. Under `"drop-oldest"` and `"drop-newest"`, it is not used (writes are resolved immediately).
545
+
546
+
The synchronous methods ({{Writer/writeSync()}}, {{Writer/writevSync()}}) operate exclusively on the slots buffer. If the slots buffer has space, the batch is placed directly into it and `true` is returned. If the slots buffer is full, the synchronous method returns `false` — it never places data into the pending writes queue.
547
+
548
+
The asynchronous methods ({{Writer/write()}}, {{Writer/writev()}}) first attempt to place the batch into the slots buffer. If the slots buffer is full, the write is placed into the pending writes queue (for `"strict"` and `"block"` policies). When the consumer reads and frees slots, pending writes are promoted from the pending queue into the slots buffer in order, and their promises resolve.
0 commit comments