Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

result.stdout is empty while result.all is not #322

Closed
ehmicky opened this issue Jun 25, 2019 · 5 comments
Closed

result.stdout is empty while result.all is not #322

ehmicky opened this issue Jun 25, 2019 · 5 comments

Comments

@ehmicky
Copy link
Collaborator

ehmicky commented Jun 25, 2019

Steps to reproduce:

import { promisify } from 'util'
import execa from 'execa'

(async () => {
  const childProcess = execa('echo', ['test'])
  await promisify(setTimeout)(1e3)

  const result = await childProcess
  console.log('stdout:', result.stdout)
  console.log('stderr:', result.stderr)
  console.log('all:', result.all)
})()
$ node index.js
stdout: 
stderr: 
all: test

Node v12.4.0
Ubuntu 19.10
Execa 2.0.0

@ehmicky ehmicky changed the title result.stdout is empty when it was not expected to result.stdout is empty while result.all is not Jun 26, 2019
@ehmicky
Copy link
Collaborator Author

ehmicky commented Jun 26, 2019

Reduced the issue to the following code (which is based on what execa does internally):

const childProcess = require('child_process');
const getStream = require('get-stream');
const mergeStream = require('merge-stream');

const bug = async () => {
	const spawned = childProcess.spawn('echo', ['test']);

	const allStream = mergeStream(spawned.stdout);

	spawned.on('exit', async () => {
		const stdout = await getStream(spawned.stdout);
		const all = await getStream(allStream);

		console.log({stdout, all});
	});
};

bug();
$ node bug.js
{ stdout: '', all: 'test\n' }

@ehmicky
Copy link
Collaborator Author

ehmicky commented Jun 26, 2019

The problem might be the following: when a childProcess exits (exit event), its stdout and stderr are flushed and closed by Node.js.

A closed stream cannot be read from nor piped from. However childProcess.stdout|stderr.pipe() is setup by childProcess.then(). We purposely defer that call in case users prefer using the streams directly instead of the returned promise. This means if childProcess.then() happens after childProcess exit event, stdout|stderr will be empty.

On one hand child process streams being cleaned up on exit is a good thing as it prevents memory leak. On the other hand there might be cases where users might want to defer a child process streams consumption, e.g. when it is passed to another consumer. We could stop deferring stream consumption, but that has issues as well. @sindresorhus I would need your feedback on this as this is tricky.


A second related (but distinct) issue is that this does not apply to childProcess.all because it's handled differently from childProcess.stdout|stderr. I think the reason might be either that:

I think this we should deal with the first problem before checking out what's happening with childProcess.all.

@ehmicky
Copy link
Collaborator Author

ehmicky commented Jul 15, 2019

The second issue seems to be because all is always piped before childProcess.then(). When a stream is piped before get-stream starts, it works.

@ehmicky
Copy link
Collaborator Author

ehmicky commented Jul 15, 2019

PR at #351.

@ehmicky
Copy link
Collaborator Author

ehmicky commented Oct 6, 2019

This is not an issue, see #351 (comment)

@ehmicky ehmicky closed this as completed Oct 6, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant