|
|
|
@ -27,7 +27,7 @@ type Config struct { |
|
|
|
|
|
|
|
|
|
// Dir is the directory the process will be run in. If not set then the
|
|
|
|
|
// process is run in the same directory as this parent process.
|
|
|
|
|
Dir string |
|
|
|
|
Dir string `yaml:"dir"` |
|
|
|
|
|
|
|
|
|
// MinWait and MaxWait are the minimum and maximum amount of time between
|
|
|
|
|
// restarts that RunProcess will wait.
|
|
|
|
@ -42,6 +42,10 @@ type Config struct { |
|
|
|
|
//
|
|
|
|
|
// Defalts to 10 seconds.
|
|
|
|
|
SigKillWait time.Duration `yaml:"sigKillWait"` |
|
|
|
|
|
|
|
|
|
// NoRestartOn indicates which exit codes should result in the process not
|
|
|
|
|
// being restarted any further.
|
|
|
|
|
NoRestartOn []int `yaml:"no_restart_on"` |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (cfg Config) withDefaults() Config { |
|
|
|
@ -63,14 +67,15 @@ func (cfg Config) withDefaults() Config { |
|
|
|
|
|
|
|
|
|
// RunProcessOnce runs the process described by the Config (though it doesn't
|
|
|
|
|
// use all fields from the Config). The process is killed if the context is
|
|
|
|
|
// canceled.
|
|
|
|
|
// canceled. The exit status of the process is returned, or -1 if the process
|
|
|
|
|
// was never started.
|
|
|
|
|
//
|
|
|
|
|
// It returns nil if the process exits normally with a zero status. It returns
|
|
|
|
|
// an error otherwise.
|
|
|
|
|
//
|
|
|
|
|
// The stdout and stderr of the process will be written to the given Logger, as
|
|
|
|
|
// well as various runtime events.
|
|
|
|
|
func RunProcessOnce(ctx context.Context, logger Logger, cfg Config) error { |
|
|
|
|
func RunProcessOnce(ctx context.Context, logger Logger, cfg Config) (int, error) { |
|
|
|
|
|
|
|
|
|
cfg = cfg.withDefaults() |
|
|
|
|
|
|
|
|
@ -106,13 +111,13 @@ func RunProcessOnce(ctx context.Context, logger Logger, cfg Config) error { |
|
|
|
|
|
|
|
|
|
stdout, err := cmd.StdoutPipe() |
|
|
|
|
if err != nil { |
|
|
|
|
return fmt.Errorf("getting stdout pipe: %w", err) |
|
|
|
|
return -1, fmt.Errorf("getting stdout pipe: %w", err) |
|
|
|
|
} |
|
|
|
|
defer stdout.Close() |
|
|
|
|
|
|
|
|
|
stderr, err := cmd.StderrPipe() |
|
|
|
|
if err != nil { |
|
|
|
|
return fmt.Errorf("getting stderr pipe: %w", err) |
|
|
|
|
return -1, fmt.Errorf("getting stderr pipe: %w", err) |
|
|
|
|
} |
|
|
|
|
defer stderr.Close() |
|
|
|
|
|
|
|
|
@ -120,7 +125,7 @@ func RunProcessOnce(ctx context.Context, logger Logger, cfg Config) error { |
|
|
|
|
fwdOutPipe(stderr) |
|
|
|
|
|
|
|
|
|
if err := cmd.Start(); err != nil { |
|
|
|
|
return fmt.Errorf("starting process: %w", err) |
|
|
|
|
return -1, fmt.Errorf("starting process: %w", err) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// go-routine which will sent interrupt if the context is cancelled. Also
|
|
|
|
@ -148,11 +153,14 @@ func RunProcessOnce(ctx context.Context, logger Logger, cfg Config) error { |
|
|
|
|
|
|
|
|
|
wg.Wait() |
|
|
|
|
|
|
|
|
|
if err := cmd.Wait(); err != nil { |
|
|
|
|
return fmt.Errorf("process exited: %w", err) |
|
|
|
|
err = cmd.Wait() |
|
|
|
|
exitCode := cmd.ProcessState.ExitCode() |
|
|
|
|
|
|
|
|
|
if err != nil { |
|
|
|
|
return exitCode, fmt.Errorf("process exited: %w", err) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return nil |
|
|
|
|
return exitCode, nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// RunProcess is a process (configured by Config) until the context is canceled,
|
|
|
|
@ -172,19 +180,25 @@ func RunProcess(ctx context.Context, logger Logger, cfg Config) { |
|
|
|
|
|
|
|
|
|
for { |
|
|
|
|
start := time.Now() |
|
|
|
|
err := RunProcessOnce(ctx, logger, cfg) |
|
|
|
|
exitCode, err := RunProcessOnce(ctx, logger, cfg) |
|
|
|
|
took := time.Since(start) |
|
|
|
|
|
|
|
|
|
if err != nil { |
|
|
|
|
logger.Printf("%v", err) |
|
|
|
|
logger.Printf("exit code %d, %v", exitCode, err) |
|
|
|
|
} else { |
|
|
|
|
logger.Println("exit status 0") |
|
|
|
|
logger.Println("exit code 0") |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if err := ctx.Err(); err != nil { |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
for i := range cfg.NoRestartOn { |
|
|
|
|
if cfg.NoRestartOn[i] == exitCode { |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
wait = ((wait * 2) - took).Truncate(time.Millisecond) |
|
|
|
|
|
|
|
|
|
if wait < cfg.MinWait { |
|
|
|
|