diff --git a/utils/daemonize.go b/utils/daemonize.go index b25cb2d..baa25a1 100644 --- a/utils/daemonize.go +++ b/utils/daemonize.go @@ -7,6 +7,7 @@ import ( "io" "os" "path/filepath" + "syscall" "github.com/VividCortex/godaemon" "github.com/leonsodhi/lockfile" @@ -24,11 +25,10 @@ func ResolvePath(path string) string { } func Daemonize(logFilePath, pidFilePath string) { - if os.Getenv("__DAEMON_CWD") == "" { cwd, err := os.Getwd() if err != nil { - fmt.Fprintln(os.Stderr, "Cannot determine working directory: %v", err) + fmt.Fprintf(os.Stderr, "Cannot determine working directory: %v\n", err) os.Exit(1) } os.Setenv("__DAEMON_CWD", cwd) @@ -36,13 +36,13 @@ func Daemonize(logFilePath, pidFilePath string) { logFile, err := os.OpenFile(logFilePath, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0666) if err != nil { - fmt.Fprintln(os.Stderr, "Could not open local log file: %v", err) + fmt.Fprintf(os.Stderr, "Could not open local log file: %v\n", err) os.Exit(1) } stdout, stderr, err := godaemon.MakeDaemon(&godaemon.DaemonAttr{CaptureOutput: true}) if err != nil { - fmt.Fprintln(os.Stderr, "Could not Daemonize: %v", err) + fmt.Fprintf(os.Stderr, "Could not Daemonize: %v\n", err) os.Exit(1) } @@ -54,10 +54,25 @@ func Daemonize(logFilePath, pidFilePath string) { }() lock, err := lockfile.New(pidFilePath) + + removePidFile := func() { + fmt.Fprintf(os.Stderr, "Removing %s\n", pidFilePath) + lock.Unlock() + } + err = lock.TryLock() if err != nil { - fmt.Println("Cannot lock \"%v\": %v", lock, err) + fmt.Fprintf(os.Stderr, "Cannot lock \"%v\", error was %v\n", lock, err) + + // Temporary workaround to transition from existing daemon + if err.Error() == "os: process already finished" { + removePidFile() + } + os.Exit(1) } + SignalHandlers[syscall.SIGINT] = removePidFile // Terminate + SignalHandlers[syscall.SIGTERM] = removePidFile // Terminate + SignalHandlers[syscall.SIGQUIT] = removePidFile // Stop gracefully } diff --git a/utils/signals.go b/utils/signals.go index dc124d3..5ff9ec9 100644 --- a/utils/signals.go +++ b/utils/signals.go @@ -3,15 +3,46 @@ package utils import ( + "fmt" + "io/ioutil" "os" + "os/signal" "runtime" "syscall" - "os/signal" - "io/ioutil" ) +var SignalHandlers = map[os.Signal]func(){ + syscall.SIGUSR1: dumpStacks, // Dump goroutines stacks +} + +func AddSignalHandlers() { + var trapped []os.Signal + for k := range SignalHandlers { + trapped = append(trapped, k) + } + + signals := make(chan os.Signal, 1) + signal.Notify(signals, trapped...) + + go func() { + for sig := range signals { + if f, found := SignalHandlers[sig]; found { + fmt.Fprintf(os.Stderr, "Handling signal: %v\n", sig) + f() + } + + switch sig { + case syscall.SIGINT, syscall.SIGTERM: + os.Exit(128 + int(sig.(syscall.Signal))) + case syscall.SIGQUIT: + os.Exit(0) + } + } + }() +} + // Mostly copied from Docker -func dumpStacks() { +func dumpStacks() { var ( buf []byte stackSize int @@ -28,25 +59,8 @@ func dumpStacks() { f, err := ioutil.TempFile("", "r_s_stacktrace") defer f.Close() - if (err == nil) { + if err == nil { f.WriteString(string(buf)) } - -} - -func AddSignalHandlers() { - sigChan := make(chan os.Signal, 1) - go func() { - for sig := range sigChan { - go func(sig os.Signal) { - switch sig { - case syscall.SIGUSR1: - dumpStacks() - } - }(sig) - - } - }() - signal.Notify(sigChan, syscall.SIGUSR1) }