Node: doc: AsyncGenerator + Writable + unhandled exception

Created on 1 Sep 2019  路  5Comments  路  Source: nodejs/node

Given the examples of using async generators with writable streams https://nodejs.org/dist/latest-v12.x/docs/api/stream.html#stream_piping_to_writable_streams_from_async_iterators.

There seems to be an issue in that they can cause an unhandled exception if 'error' is emitted after 'finish' (which is currently possible in some cases even with core streams). once will release the 'error' handler on completion ('finish'). I would personally discourage using it as in the example, i.e.

I would replace:

UNSAFE

const { once } = require('events');

const writable = fs.createWriteStream('./file');

(async function() {
  const readable = Readable.from(iterator);
  readable.pipe(writable);
  // Ensure completion without errors.
  await once(writable, 'finish');
})();

with

SAFE

const finished = util.promisify(stream.finished);

const writable = fs.createWriteStream('./file');

(async function() {
  const readable = Readable.from(iterator);
  readable.pipe(writable);
  // Ensure completion without errors.
  await finished(writable);
})();

or

const pipeline = util.promisify(stream.pipeline);

const writable = fs.createWriteStream('./file');

(async function() {
  const readable = Readable.from(iterator);
  await pipeline(readable, writable);
})();

and

UNSAFE

const { once } = require('events');

const writable = fs.createWriteStream('./file');

(async function() {
  for await (const chunk of iterator) {
    // Handle backpressure on write().
    if (!writable.write(chunk))
      await once(writable, 'drain');
  }
  writable.end();
  // Ensure completion without errors.
  await once(writable, 'finish');
})();

with

SAFE

const { once } = require('events');
const finished = util.promisify(stream.finished);

const writable = fs.createWriteStream('./file');

(async function() {
  for await (const chunk of iterator) {
    // Handle backpressure on write().
    if (!writable.write(chunk))
      await once(writable, 'drain');
  }
  writable.end();
  // Ensure completion without errors.
  await finished(writable);
})();

Possibly with a note on why once is not appropriate in this situation.

doc good first issue stream

Most helpful comment

I'd like to work on this. I will create a PR with required updates to the doc.

All 5 comments

@mcollina Want a PR?

@ronag Please, either that or let someone new take it.

let someone new take it.

+1

+1 on a PR.

I'd like to work on this. I will create a PR with required updates to the doc.

Was this page helpful?
0 / 5 - 0 ratings