bustle / streaming-iterables

A Swiss army knife for async iterables. Designed to replace your streams.
https://www.npmjs.com/package/streaming-iterables
MIT License
43 stars 4 forks source link

Stream errors in writeToStream can't be caught #30

Closed dotboris closed 5 years ago

dotboris commented 5 years ago

It seems like writeToStream does not catch stream errors. Since the errors are not caught the node process is killed.

Here's an example:

const iter = require('streaming-iterables');

async function * lines () {
  yield 'foo\n';
  yield 'bar\n';
  yield 'baz\n';
  yield 'qux\n';
}

async function main () {
  await iter.writeToStream(process.stdout, lines());
}

main()
  .catch(err => {
    console.error('Caught exception!');
    console.error(err.stack);
    process.exitCode = 1;
  });

If I call this normally it works as expect

$ node __scratch/test.js
foo
bar
baz
qux

If I force an error (in this case an EPIPE), we see that the process crashes and the error can't be caught.

$ node __scratch/test.js | head -n1
foo
events.js:174
      throw er; // Unhandled 'error' event
      ^

Error: write EPIPE
    at WriteWrap.afterWrite [as oncomplete] (net.js:782:14)
Emitted 'error' event at:
    at onwriteError (_stream_writable.js:431:12)
    at onwrite (_stream_writable.js:456:5)
    at _destroy (internal/streams/destroy.js:40:7)
    at Socket.dummyDestroy [as _destroy] (internal/process/stdio.js:11:34)
    at Socket.destroy (internal/streams/destroy.js:32:8)
    at WriteWrap.afterWrite [as oncomplete] (net.js:784:10)
reconbot commented 5 years ago

Writable streams can error in a few ways, sync in the write, sync in the write cb, async in the write cb or from this.emit('error', ...).

It boils down to stream.write() throwing or an error event emitting. We deal with write() throwing, but we need to add support for the error event.

Why calling the write cb at different times produces an exception from stream.write() vs an error event I don't know. You'd think it would always be an event.

To make matters more complex, the write stream has a buffer, you can finish writing to it and it can error after the fact due to writes performed by this function.

While I can make this stop writing on an error, you still have to handle errors in your stream yourself.

reconbot commented 5 years ago

deployed streaming-iterables@4.1.0

dotboris commented 5 years ago

@reconbot I see the new version on NPM but I don't see a tag on github. Did you forget to push or something?