-
-
Notifications
You must be signed in to change notification settings - Fork 224
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
Promise never resolves if process output pipes are read first in node 18.14.0 #516
Comments
Hi @anomiex, Thanks for reporting this. This appears to also be a problem with 19.5.0 (but not 19.4.0). import { execa } from 'execa'
import { setTimeout } from 'node:timers/promises'
const proc = execa('echo')
await setTimeout(1e3) // Must be longer than the duration of `echo`
await proc
console.log('done')
This appears to be a bug in Node.js, which I just reported here: nodejs/node#46595 In a nutshell, the promise returned by Execa waits for stdin/stdout/stderr to complete to resolve (which is good): Line 71 in e331353
Under the hood, this relies on While the underlying bug is being worked out by the Node.js team, the following workaround is available for Execa users: For instance, to re-take your example: import { execa } from 'execa';
import readline from 'node:readline';
const readProcess = async (proc) => {
const rl = readline.createInterface( {
input: proc.stdout,
crlfDelay: Infinity,
} );
let ct = 0;
for await ( const l of rl ) {
ct++;
}
console.log( `Saw ${ct} files` );
};
const proc = execa( 'find', [ '/usr/bin', '-type', 'f' ], { stdio: [ 'ignore', 'pipe', 'inherit' ] } );
const [result] = await Promise.all([proc, readProcess(proc)]);
console.log( `Process exit code: ${result.exitCode}` ); This is actually good practice since leaving promises without a |
Thanks for the link to the node bug. In our case, we just set
Not really. The |
If the For example: import { execa } from 'execa';
import readline from 'node:readline';
const proc = execa( 'find_mispelled', [ '/usr/bin', '-type', 'f' ], { stdio: [ 'ignore', 'pipe', 'inherit' ] } );
const rl = readline.createInterface( {
input: proc.stdout,
crlfDelay: Infinity,
} );
let ct = 0;
console.log('Start loop');
for await ( const l of rl ) {
ct++;
}
console.log('End loop');
const result = await proc;
console.log( `Process exit code: ${result.exitCode}` ); The binary
|
Huh, that's unexpected. I see nodejs/node#43326 (comment) already mentions something similar. |
The underlying Node.js bug has now been fixed in Node |
Consider this code:
When run with execa 6.1.0 and node 18.14.0, node will exit without ever finishing the
await
, presumably due to the event loop becoming empty.This seems to be something of the opposite of the caution that's already in the documentation for the
buffer
option:Apparently starting with node 18.14.0 the converse is also true: if you're going to read the output of
stdout
orstderr
(orall
) yourself then you need to setbuffer: false
or the returned promise will not be resolved/rejected.I don't know if there's a way around this (maybe you could check if the streams'
readableEnded
is true before trying to create promises for them? Or create the buffer streams before returning fromexeca()
?) or if this behavior change in node is itself a bug.The text was updated successfully, but these errors were encountered: