Re: [whatwg/streams] pipeTo: Read fulfilled after shutdown started (Issue #1207)

Thinking about it some more, I don't think that will work. I think I got a bit confused when I wrote my previous reply. 😬 

The problem is not that we *start* a new read after the destination has become errored. We're already awaiting `writer.ready` which is always rejected *immediately* in [step 8 of WritableStreamStartErroring](https://streams.spec.whatwg.org/commit-snapshots/908ceddfb813ec0d9c727393edfb13d810e694f1/#writable-stream-start-erroring). It *might* be possible that the destination becomes errored *during the same microtask* that `writer.ready` becomes resolved, so a synchronous check may still be appropriate.

The real problem is when there's *already* a pending read, and *then* the destination becomes errored at the same time that a chunk is enqueued onto the source. So:
```javascript
writableController.error("💥");
readableController.enqueue("a");
```
Erroring the writable will *asynchronously* reject `writer.closed`, but enqueuing a chunk will *synchronously* call the read request's chunk steps. Even if we added a synchronous check [here](https://github.com/whatwg/streams/blob/908ceddfb813ec0d9c727393edfb13d810e694f1/reference-implementation/lib/abstract-ops/readable-streams.js#L204-L217):
```javascript
ReadableStreamDefaultReaderRead(
  reader,
  {
    chunkSteps: chunk => {
      if (dest._state !== 'writable') {
        // ...now what? 🤷‍♂️
      }
      currentWrite = transformPromiseWith(
        WritableStreamDefaultWriterWrite(writer, chunk), undefined, () => {}
      );
      resolveRead(false);
    },
    closeSteps: () => resolveRead(true),
    errorSteps: rejectRead
  }
);
```
...we would still be unable to do anything useful with `chunk`. Ideally, we'd put it back *at the start* of the source's queue, but we don't have a way to do that.

The only way we can avoid this is if we can *synchronously* release the reader as soon as the destination becomes errored, i.e. attach an error callback to the writer.

(Note that doing `enqueue()` followed by `error()` *can* result in the newly enqueued chunk being successfully written to the destination *before* the destination becomes errored. The read request's chunk steps synchronously call `writer.write()`, which can synchronously call `sink.write()` and complete the write. So we don't "accidentally" drop a chunk in this case.)

-- 
Reply to this email directly or view it on GitHub:
https://github.com/whatwg/streams/issues/1207#issuecomment-1017947644

You are receiving this because you are subscribed to this thread.

Message ID: <whatwg/streams/issues/1207/1017947644@github.com>

Received on Thursday, 20 January 2022 21:34:38 UTC