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
Improve piping processes #834
Merged
Merged
Conversation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
sindresorhus
requested changes
Feb 21, 2024
This is a really good improvement 👍 |
Co-authored-by: Sindre Sorhus <sindresorhus@gmail.com>
Co-authored-by: Sindre Sorhus <sindresorhus@gmail.com>
Co-authored-by: Sindre Sorhus <sindresorhus@gmail.com>
Co-authored-by: Sindre Sorhus <sindresorhus@gmail.com>
Co-authored-by: Sindre Sorhus <sindresorhus@gmail.com>
Co-authored-by: Sindre Sorhus <sindresorhus@gmail.com>
Ready for another round of review. 👍 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Fixes #745
Fixes #753
This is a major improvement for piping multiple processes. Currently
source.pipe(destination)
is mostly just a shortcut tosource.stdout.pipe(destination.stdin)
.From looking at other projects, piping processes is usually implemented either like the above, or by relying on a shell like Bash. IMHO shells were initially designed to be run in an interactive terminal, not to be used in a programmatic context. They cannot easily provide with many features that are useful in a programmatic context. Such as, in the case of piping:
stderr
This PR adds the following features.
Bash convention
This follows the Bash convention when it comes to many aspects including: exit code, termination of processes, signals, closing streams, etc.
One important point is: process termination happens by closing
stdout
andstdin
, not by sending termination signals. This is how Bash behaves. This allows processes to exit gracefully.(Side note:
SIGPIPE
is not sent by the shell, but by the OS when the source process tries to write to the destination process after itsstdin
closed)Error handling
Both processes are awaited. Previously, errors in the first process would crash the parent process.
Full pipe information
.pipe()
resolves with the last process' result. Additionally, the result from the previous process in the pipe is available asresult.pipedFrom[*]
. This is recursive, so this works when piping a series of processes. This is available on errors too, which is useful for debugging.Cancellation
An
AbortSignal
can be passed to thesignal
option. When aborted, the processes are unpiped. They are not terminated. This is useful for:This uses
merge-streams
.remove()
method under-the-hood.1-n and n-1 piping
While piping one process to multiple processes (1-n) is simple, piping multiple processes to one process (n-1) is hard. This is because the last process must close the destination's
stdin
. There are several things that can happen to bothstdout
andstdin
(ending too early, erroring, not being read/written to, being unpiped) and handling it correctly (propagating the error to users, allowing graceful exits, ensuring processes are not left hanging) is tricky.With this PR, n-1 piping just works without user having to do anything, as Execa keeps track of which process is being piped, and uses
merge-streams
under-the-hood.The tests are trying to run 100 processes at once, for both 1-n and n-1, and this works. I have tried up to 5000 processes at once locally, and it worked. After that, I started hitting the OS limits (
pthread_create: Resource temporarily unavailable
), although those can be configured. This does not leak resources, e.g. does not emit anymaxListeners
warnings.Process cleanup
If the arguments/options are invalid, we close the processes'
stdout
/stdin
to ensure they are not left hanging due to a programming mistake.