You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Add Promise-based versions of child_process #38823
Is your feature request related to a problem? Please describe.
It would be nice if child_process functionality, such as exec, had Promised based versions by default. Currently it does not, see https://nodejs.org/api/child_process.html
Describe the solution you'd like
A new child_process/promises import path that can be used similar to how fs promises are used:
// Using ESM Module syntax:import{exec}from'child_process/promises';try{const{ stdout }=awaitexec('sysctl -n net.ipv4.ip_local_port_range');console.log('successfully executed the child process command');}catch(error){console.error('there was an error:',error.message);}
Describe alternatives you've considered
I am already using const exec = util.promisify(process.exec); but that is not as nice. And this new proposal follows along what is happening in other Node.js APIs.
changed the title [-]Add Promise-based versions of Child process (child_process)[/-][+]Add Promise-based versions of child process (child_process)[/+]on May 28, 2021
There has been no activity on this feature request for 5 months and it is unlikely to be implemented. It will be closed 6 months after the last non-automated comment.
If this method is invoked as its util.promisify()ed version, it returns a Promise for an Object with stdout and stderr properties.
Ergo the feature request is about not having to do e.g. const exec = util.promisify(require('child_process').exec); like is given as an example in your own documentation.
We might be able to take inspiration from the popular npm module execa when designing / implementing a more convenient promise based child_process api. I've used it for many years and it's a breeze to work with.
Oh hey, this issue again. Coming up at the 2.5 year mark.
So, I think the initial ask here is based on the mistaken assumption that promise == async == non-blocking / work done in background. Read #41964 (comment) to dispel yourself of that illusion.
The post facto counterargument offered in #38823 (comment) is unconvincing: "okay, maybe it's not really async but it reads nicer."
No one (to my utter lack of surprise) has offered up:
a credible sketch of what a promise-based API should look like ("be like execa" doesn't cut it), and
a good analysis of the material benefits a new API offers over the existing child_process module
@aduh95 tried (1) and concluded you end up sacrificing functionality. My answer to (2) is "practically nil."
Really the only argument people have advanced for keeping this issue open is "but it has many upvotes!"
Good thing I'm not swayed by popularity contests. Closing.
Reacted by John Firebaugh, Tobias Hernstig, Nicholas Kyriakides and Landon Schropp
So, I think the initial ask here is based on the mistaken assumption that promise == async == non-blocking / work done in background. Read #41964 (comment) to dispel yourself of that illusion.
Correct me if I'm wrong but I don't think what OP in this issue (#38823) is asking is for an async version of uv_spawn. I think he's asking about:
All of these 3 function should have a corresponding child_process/promises counterpart where the callback has been removed and the function instead returns something like a ChildProcess+Promise hybrid (or an object containing { promise, process }), where the promise will resolve or reject once the process terminates, and stdout,stderr should be accessible in some easy way, like for example properties on the resolved object or properties on the rejected Error object.
In addition to that, I would personally like to see the following:
If the process returns a non-zero exit code, the promise should be rejected.
a new timeout property that when set, will send a SIGKILL to the process after the process has run for timeout ms. The error object should the contain a boolean timedOut: true
This would allow the user to do something like this:
import{exec}from'child_process/promises';try{const{ stdout, stderr }=awaitspawn('ls',['/']);console.log('child process finished successfully and the result was:',stdout);}catch(err){console.error('Process exited with code',err.exitCode,err);console.error('stderr was:',error.stderr)}
child_process.fork and child_process.spawn should have a callback that's called with the output when process terminates, just like child_process.exec
I've read through the comments again but I really don't know how you came to that conclusion... and anyway, that misses the point of fork() and spawn(). If you want exec-like behavior, use exec().
If the process returns a non-zero exit code, the promise should be rejected.
Bad design choice. Many child processes terminate with a non-zero exit code - but in a benign fashion - after e.g. SIGPIPE or ^C.
// Using ESM Module syntax:import{exec}from'child_process/promises';try{const{ stdout }=awaitexec('sysctl -n net.ipv4.ip_local_port_range');console.log('successfully executed the child process command');}catch(error){console.error('there was an error:',error.message);
Ergo exec() can already be used with async/await but needs and extra promisify. I cannot grok still from this thread why child_process/promises could just do this wrapping and export it.
It's better if you split that out into a new issue. A promise-ified child_process.exec may be useful (or maybe not, I'm reserving judgment) but this issue is about promise-ifying the child_process module wholesale. Different goalposts.
@bnoordhuis I do not think I ever put expectations on the entire module to be promisified. The intention was to make the functions that are feasible into async/await, such as exec.
This topic was about even creating child_process/promises to start with the ones that can be promisified. That might be exec for now, but maybe more in the future. I do not know, it has to be done for whatever makes sense.
But for anything to even happen a child_process/promises module is a prerequisite.
Do you still want a new issue even though this seems to be an unclear ask from me from the start, that obviously everyone has read differently into.
I do not think I ever put expectations on the entire module to be promisified.
It's right there in the title.
The intention was to make the functions that are feasible into async/await, such as exec.
Sure, that's a more reasonable ask. If you'd been clear about that from the start, that would've saved a lot of back and forth.
The reason you can util.promisify(child_process.exec) and execFile but not spawn or fork is because people already thought through the use cases, concluded promises make sense for the former but not the latter, and added the appropriate hooks (the child_process.exec[util.promisify.custom] hook.)
You're welcome to open a pull request that adds a child_process/promises module and see how it's received.
I do not think I ever put expectations on the entire module to be promisified.
It's right there in the title.
It never goes into the extent. The title does not mention anything about the entire module being promisfied. Multiple posts follow up talking about exec only. I can amend the title/description even more, but closing it and opening a new one will lose upvotes and thus people tracking this. But I did it anyway to stop the fastidious back and forth: #49904
Activity
Trott commentedon May 27, 2021
@nodejs/child_process
[-]Add Promise-based versions of Child process (child_process)[/-][+]Add Promise-based versions of child process (child_process)[/+][-]Add Promise-based versions of child process (child_process)[/-][+]Add Promise-based versions of child_process[/+]github-actions commentedon Mar 24, 2022
There has been no activity on this feature request for 5 months and it is unlikely to be implemented. It will be closed 6 months after the last non-automated comment.
For more information on how the project manages feature requests, please consult the feature request management document.
thernstig commentedon Mar 24, 2022
Unstale since it has 6 upvotes and makes great sense.
bnoordhuis commentedon Mar 26, 2022
See discussion in #41964, #41964 (comment) in particular. Thanks for the suggestion but closing as a wontfix.
thernstig commentedon Mar 27, 2022
@bnoordhuis please re-open this issue. There are parts that can be given async versions directly, as indicate by Node.js documentation.
Please see https://nodejs.org/api/child_process.html#child_processexeccommand-options-callback:
Ergo the feature request is about not having to do e.g.
const exec = util.promisify(require('child_process').exec);like is given as an example in your own documentation.26 remaining items
thernstig commentedon Jul 4, 2023
Wish the github-actions did not try to close features with 20+ upvotes
bnoordhuis commentedon Jul 5, 2023
I'm giving this issue a few more months but if nothing happens, I'm going to close it out again, upvotes or not.
mifi commentedon Sep 26, 2023
We might be able to take inspiration from the popular npm module
execawhen designing / implementing a more convenient promise based child_process api. I've used it for many years and it's a breeze to work with.bnoordhuis commentedon Sep 26, 2023
Oh hey, this issue again. Coming up at the 2.5 year mark.
So, I think the initial ask here is based on the mistaken assumption that promise == async == non-blocking / work done in background. Read #41964 (comment) to dispel yourself of that illusion.
The post facto counterargument offered in #38823 (comment) is unconvincing: "okay, maybe it's not really async but it reads nicer."
No one (to my utter lack of surprise) has offered up:
@aduh95 tried (1) and concluded you end up sacrificing functionality. My answer to (2) is "practically nil."
Really the only argument people have advanced for keeping this issue open is "but it has many upvotes!"
Good thing I'm not swayed by popularity contests. Closing.
mifi commentedon Sep 27, 2023
Correct me if I'm wrong but I don't think what OP in this issue (#38823) is asking is for an async version of uv_spawn. I think he's asking about:
child_process.forkandchild_process.spawnshould have a callback that's called with the output when process terminates, just likechild_process.exechas.child_process/promisescounterpart where the callback has been removed and the function instead returns something like a ChildProcess+Promise hybrid (or an object containing{ promise, process }), where the promise will resolve or reject once the process terminates, andstdout,stderrshould be accessible in some easy way, like for example properties on the resolved object or properties on the rejected Error object.In addition to that, I would personally like to see the following:
timeoutproperty that when set, will send a SIGKILL to the process after the process has run fortimeoutms. The error object should the contain a booleantimedOut: trueThis would allow the user to do something like this:
bnoordhuis commentedon Sep 27, 2023
I've read through the comments again but I really don't know how you came to that conclusion... and anyway, that misses the point of fork() and spawn(). If you want exec-like behavior, use exec().
Bad design choice. Many child processes terminate with a non-zero exit code - but in a benign fashion - after e.g. SIGPIPE or ^C.
Already exists.
thernstig commentedon Sep 27, 2023
Honestly the ask is basically that
child_process/promisescould just return a variant such asconst exec = util.promisify(process.exec);as a conventience. To then already be used like the already existing code examples of this from https://nodejs.org/api/child_process.html#child_processexeccommand-options-callback:Ergo
exec()can already be used with async/await but needs and extrapromisify. I cannot grok still from this thread whychild_process/promisescould just do this wrapping and export it.bnoordhuis commentedon Sep 27, 2023
It's better if you split that out into a new issue. A promise-ified child_process.exec may be useful (or maybe not, I'm reserving judgment) but this issue is about promise-ifying the child_process module wholesale. Different goalposts.
thernstig commentedon Sep 27, 2023
@bnoordhuis I do not think I ever put expectations on the entire module to be promisified. The intention was to make the functions that are feasible into async/await, such as
exec.I explicitly gave an example of the
fsmodule which has undergone the same journey. I.e. if you look at https://nodejs.org/docs/latest-v10.x/api/fs.html there were only very few promise-based versions as compared to https://nodejs.org/api/fs.html which now has many. But it hard to start from somewhere.This topic was about even creating
child_process/promisesto start with the ones that can be promisified. That might beexecfor now, but maybe more in the future. I do not know, it has to be done for whatever makes sense.But for anything to even happen a
child_process/promisesmodule is a prerequisite.Do you still want a new issue even though this seems to be an unclear ask from me from the start, that obviously everyone has read differently into.
bnoordhuis commentedon Sep 27, 2023
It's right there in the title.
Sure, that's a more reasonable ask. If you'd been clear about that from the start, that would've saved a lot of back and forth.
The reason you can
util.promisify(child_process.exec)and execFile but not spawn or fork is because people already thought through the use cases, concluded promises make sense for the former but not the latter, and added the appropriate hooks (thechild_process.exec[util.promisify.custom]hook.)You're welcome to open a pull request that adds a child_process/promises module and see how it's received.
thernstig commentedon Sep 27, 2023
It never goes into the extent. The title does not mention anything about the entire module being promisfied. Multiple posts follow up talking about
execonly. I can amend the title/description even more, but closing it and opening a new one will lose upvotes and thus people tracking this. But I did it anyway to stop the fastidious back and forth: #49904dead-claudia commentedon Sep 9, 2024
Got a (mostly) concrete proposal in #54799.