// Terminate kills the application func (a *App) Terminate() { a.signalLock.Lock() defer a.signalLock.Unlock() a.stopPolling() a.forAllServices(deregisterService) // Run and wait for preStop command to exit utils.RunWithFields(a.PreStopCmd, log.Fields{"process": "PreStop"}) cmd := a.Command if cmd == nil || cmd.Process == nil { // Not managing the process, so don't do anything return } if a.StopTimeout > 0 { if err := cmd.Process.Signal(syscall.SIGTERM); err != nil { log.Warnf("Error sending SIGTERM to application: %s", err) } else { time.AfterFunc(time.Duration(a.StopTimeout)*time.Second, func() { log.Infof("Killing Process %#v", cmd.Process) cmd.Process.Kill() }) return } } log.Infof("Killing Process %#v", a.Command.Process) cmd.Process.Kill() }
// OnChange runs the backend's onChange command, returning the results func (b *Backend) OnChange() (int, error) { defer func() { // reset command object because it can't be reused b.onChangeCmd = utils.ArgsToCmd(b.onChangeCmd.Args) }() exitCode, err := utils.RunWithFields(b.onChangeCmd, log.Fields{"process": "OnChange", "backend": b.Name}) return exitCode, err }
// Run starts the application and blocks until finished func (a *App) Run() { // Set up handlers for polling and to accept signal interrupts if 1 == os.Getpid() { reapChildren() } args := getArgs(flag.Args()) command, err := utils.ParseCommandArgs(args) if err != nil { log.Errorf("Unable to parse command arguments: %v", err) } a.handleSignals() // Run the preStart handler, if any, and exit if it returns an error if preStartCode, err := utils.RunWithFields(a.PreStartCmd, log.Fields{"process": "PreStart"}); err != nil { os.Exit(preStartCode) } a.handleCoprocesses() a.handlePolling() if len(args) != 0 { // Run our main application and capture its stdout/stderr. // This will block until the main application exits and then os.Exit // with the exit code of that application. a.Command = command command.Stderr = os.Stderr command.Stdout = os.Stdout code, err := utils.ExecuteAndWait(command) if err != nil { log.Println(err) } // Run the PostStop handler, if any, and exit if it returns an error if postStopCode, err := utils.RunWithFields(a.PostStopCmd, log.Fields{"process": "PostStop"}); err != nil { os.Exit(postStopCode) } os.Exit(code) } // block forever, as we're polling in the two polling functions and // did not os.Exit by waiting on an external application. select {} }
// CheckHealth runs the service's health command, returning the results func (s *Service) CheckHealth() (int, error) { defer func() { // reset command object because it can't be reused if s.healthCheckCmd != nil { s.healthCheckCmd = utils.ArgsToCmd(s.healthCheckCmd.Args) } }() // if we have a valid Service but there's no health check // set, assume it always passes (ex. telemetry service). if s.healthCheckCmd == nil { return 0, nil } exitCode, err := utils.RunWithFields(s.healthCheckCmd, log.Fields{"process": "health", "serviceName": s.Name, "serviceID": s.ID}) return exitCode, err }