command: Improve error handling for stdout
When spawning a command, we always make sure to eventually end up
calling Wait()
on that command. The Wait()
function will end up
doing a bunch of housekeeping, like closing standard streams and
updating our metrics.
Part of the logic also relates to stdout, which we copy into an
io.Discard
writer. This is done such that the command will not
deadlock in case the pipe buffer has been filled, but there is no reader
because we wait for the command to finish. This strategy has two
significant downsides though:
- Reading the output on the Go side will not cause an error, which
may cause us to end up with a successfully read buffer that only
contains partial output.
- The command will continue to write its complete output to stdout
without noticing that anything is wrong. We don't send a signal,
and stdout is being drained alright, so it cannot realize that it
should maybe stop what it's doing.
Address these issues by changing the strategy to close stdout instead of draining. This will cause the Go side to receive an error upon reading stdout, and will cause the process' side to receive a SIGPIPE signal upon writing to stdout. So overall, we are in a much better position to detect any mishandling.
Closes Address the race with command execution and con... (#5021 - closed).