I want to implement a "process wrapper" in Go. Basically what it will do, is launch a process (lets say a node server) and monitor it (catch signals like SIGKILL, SIGTERM ...)
I think the way to do is to launch the node server in a go routine using syscall.Exec
:
func launchCmd(path string, args []string) { err := syscall.Exec(path, args, os.Environ()) if err != nil { panic(err) } }
Then I'd like to catch every possible signals generated by the command executed by syscall
. I'm pretty new to Go, any help would be appreciated.
Unix signal can be easily handled in Golang by using the os/signal package. We need to use a channel of type os. Signal to read signals. You can implement code to handle every type of Unix signal received by the program.
As per the golang documentation, “Channels are a typed conduit through which you can send and receive values with the channel operator, <- .” A channel allows one goroutine to signal another goroutine about a particular event.
The SIGTERM signal is a generic signal used to cause program termination. Unlike SIGKILL , this signal can be blocked, handled, and ignored. It is the normal way to politely ask a program to terminate. The shell command kill generates SIGTERM by default.
Signals are standardized messages sent to a running program to trigger specific behavior, such as quitting or error handling. They are a limited form of inter-process communication (IPC), typically used in Unix, Unix-like, and other POSIX-compliant operating systems.
There are three ways of executing a program in Go:
syscall
package with syscall.Exec, syscall.ForkExec, syscall.StartProcess os
package with os.StartProcess os/exec
package with exec.Command syscall.StartProcess is low level. It returns a uintptr
as a handle.
os.StartProcess
gives you a nice os.Process
struct that you can call Signal on. os/exec
gives you io.ReaderWriter
to use on a pipe. Both use syscall
internally.
Reading signals sent from a process other than your own seems a bit tricky. If it was possible, syscall
would be able to do it. I don't see anything obvious in the higher level packages.
To receive a signal you can use signal.Notify like this:
sigc := make(chan os.Signal, 1) signal.Notify(sigc, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT) go func() { s := <-sigc // ... do something ... }()
You just need to change the signals you're interested in listening to. If you don't specify a signal, it'll catch all the signals that can be captured.
You would use syscall.Kill or Process.Signal to map the signal. You can get the pid from Process.Pid
or as a result from syscall.StartProcess.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With