2
\$\begingroup\$

The idea here is that my executable can be started normally (in which case it runs my business logic), or it can be wrapped in a nanny process (which starts a child process to run the business logic, and if the child process dies restarts it indefinitely). Here are some more specific requirements:

  • As invisible to the caller as possible
  • STDOUT/STDERR of the child should appear to be coming from the parent (so that if I run it in a terminal, it's invisible what's happening)
  • A dead child is restarted
  • A dead parent kills the child (so that ctrl-C in a terminal is sane)

Here is what I have (working). Is there a cleaner way, or am I wasting resources somehow?

package main

import (
    "fmt"
    "os"
    "os/exec"
    "flag"
    "time"
)

var nanny string
var myparent int 

func init() {
    flag.StringVar(&nanny, "nanny", "", "execute 'run -nanny run' to run in nanny mode.")
    flag.IntVar(&myparent, "myparent", 0, "never run 'run -myparent xxx'; it is used by nanny mode.")
}

func main() {
    flag.Parse()
    if nanny != "" {
        nannymain()
    } else {
        realmain()
    }   
}

func realmain() {
    if myparent != 0 { 
        go nannywatcher()
    }   

    // ... run arbitrary business logic ...
}

func nannywatcher() {
    for {
        time.Sleep(1000 * time.Millisecond)
        if os.Getppid() != myparent {
            // We've been reparented!  If our nanny was killed someone is
            // trying to kill us, and the nanny will take care of the logging.
            // Just die.
            os.Exit(1)
        }
    }
}

func nannymain() {
    pid := os.Getpid()
    for {
        cmd := exec.Command(nanny, fmt.Sprintf("-myparent=%d", pid))
        cmd.Stdout = os.Stdout
        cmd.Stderr = os.Stderr
        cmd.Run()
        // The child died.  We will restart him.
    }
}
\$\endgroup\$
1
  • \$\begingroup\$ Do those have to be separate processes, or is it just the solution you thought of to achieve the other requirements (some business logic that outputs on STDOUT/STDERR, and a flag that executes the business logic and restarts it whenever it dies)? I can think of a cleaner & more idiomatic way to do that, but this uses goroutines instead of processes. \$\endgroup\$
    – Ted
    Commented Dec 16, 2016 at 7:06

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Browse other questions tagged or ask your own question.