add NoRestartOn config parameter

This commit is contained in:
Brian Picciano 2022-02-24 20:48:37 -07:00
parent 20cb7b9255
commit 2c5c669c72
2 changed files with 28 additions and 12 deletions

View File

@ -19,6 +19,8 @@ processes:
env:
TARGET: example.com
dir: "/tmp"
# pmux uses an exponential backoff when restarting a process, so subsequent
# restarts will each take longer and longer. minWait/maxWait indicate the
# min/max wait times between restarts of this process, respectively.

View File

@ -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 {