Skip to content

Commit

Permalink
Use Command.WaitDelay to avoid Command.Wait blocking on stdin/out/err
Browse files Browse the repository at this point in the history
Add WaitDelay to ensure cmd.Wait() returns in a reasonable timeframe if
the goroutines that cmd.Start() uses to copy Stdin/Stdout/Stderr are
blocked when copying due to a sub-subprocess holding onto them. Read
more details in these issues:

- golang/go#23019
- golang/go#50436

This isn't the original intent of kill-delay, but it seems reasonable
to reuse it in this context.

Fixes canonical#149
  • Loading branch information
benhoyt committed Aug 15, 2023
1 parent 73aa51e commit 10fa2a4
Showing 1 changed file with 15 additions and 3 deletions.
18 changes: 15 additions & 3 deletions internals/overlord/servstate/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,18 @@ func (s *serviceData) startInternal() error {
s.cmd.Stdout = logWriter
s.cmd.Stderr = logWriter

// Add WaitDelay to ensure cmd.Wait() returns in a reasonable timeframe if
// the goroutines that cmd.Start() uses to copy Stdin/Stdout/Stderr are
// blocked when copying due to a sub-subprocess holding onto them. Read
// more details in these issues:
//
// - https://github.com/golang/go/issues/23019
// - https://github.com/golang/go/issues/50436
//
// This isn't the original intent of kill-delay, but it seems reasonable
// to reuse it in this context.
s.cmd.WaitDelay = s.killDelay()

// Start the process!
logger.Noticef("Service %q starting: %s", serviceName, s.config.Command)
err = reaper.StartCommand(s.cmd)
Expand Down Expand Up @@ -616,9 +628,9 @@ func (s *serviceData) sendSignal(signal string) error {
}

// killDelay reports the duration that this service should be given when being
// asked to shutdown gracefully before being force terminated. The value
// returned will either be the services pre configured value or the default
// kill delay for pebble.
// asked to shut down gracefully before being force-terminated. The value
// returned will either be the service's pre-configured value, or the default
// kill delay if that is not set.
func (s *serviceData) killDelay() time.Duration {
if s.config.KillDelay.IsSet {
return s.config.KillDelay.Value
Expand Down

0 comments on commit 10fa2a4

Please sign in to comment.