实现基本的进程守护功能
- package main
- import (
- "context"
- "fmt"
- "github.com/shirou/gopsutil/v3/process"
- "os"
- "os/exec"
- "os/signal"
- "syscall"
- "time"
- )
- var CMD *exec.Cmd
- type Bye struct {
- Cmd *exec.Cmd
- Error error
- }
- func _clean(ctx context.Context, name string) error {
- // kill process by name
- processes, err := process.ProcessesWithContext(ctx)
- if err != nil {
- return err
- }
- for _, p := range processes {
- _name, err := p.NameWithContext(ctx)
- if err != nil {
- return err
- }
- if _name == name {
- return p.KillWithContext(ctx)
- }
- }
- return nil
- }
- func _fork(env []string) *exec.Cmd {
- // args := []string{ "atg01", "arg02", "arg03" }
- // cmd := exec.Command("./lib/app", args...)
- cmd := exec.Command("./bin/app")
- cmd.Stdout = os.Stdout
- cmd.Stderr = os.Stderr
- cmd.Env = env
- cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
- return cmd
- }
- func _exit() error {
- pid := CMD.Process.Pid
- fmt.Printf("[App pid=%d]child process(%s) existing\n", pid, CMD.String())
- CMD.Process.Release()
- err := syscall.Kill(-pid, syscall.SIGKILL)
- if err != nil {
- return err
- }
- return nil
- }
- func main() {
- /*
- daemon
- |______app
- 需要实现由 daemon 来管理 App 进程的存活
- 1. 当 daemon 进程退出, 则 App 也一并退出
- 2. 当 App 进程退出, daemon 需要把 App 进程重新启动
- */
- selfPid := os.Getpid()
- // 清理残留的 App 进程, 因为 go 监听不到 SIGKILL(kill -9)
- ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
- defer cancel()
- err := _clean(ctx, "appName")
- if err != nil {
- fmt.Printf("failed to clean old app process: %s\n", err.Error())
- return
- }
- os.Setenv("ENV_KEY", "ENV_Value") // set env if you need
- env := os.Environ()
- CMD = _fork(env)
- err = CMD.Start()
- if err != nil {
- fmt.Printf("[Daemon pid=%d]failed to start app process: %s\n", selfPid, err)
- return
- } else {
- fmt.Printf("[Daemon pid=%d]succeed start app process, app pid=%d\n", selfPid, CMD.Process.Pid)
- }
- defer _exit()
- // 监听信号
- signals := make(chan os.Signal)
- signal.Notify(signals, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGKILL, syscall.SIGQUIT)
- // 监听子进程
- done := make(chan Bye, 1)
- go func() {
- err := CMD.Wait()
- item := Bye{
- Cmd: CMD,
- Error: err,
- }
- done <- item
- }()
- for {
- select {
- case <-time.After(time.Second * 5):
- fmt.Printf("[%s]heart beat...\n", time.Now().Format("2006-01-02 15:04:05"))
- case s := <-signals:
- fmt.Printf("Daemon got siganl=%d, now[%s] to exit...\n", s, time.Now().Format("2006-01-02 15:04:05"))
- goto ForEnd
- case bye := <-done:
- if bye.Error != nil {
- fmt.Printf("[App pid=%d]process(%s) finished with error = %s\n", bye.Cmd.Process.Pid, bye.Cmd.String(), bye.Error.Error())
- }
- fmt.Printf("\n% v\n\n", bye.Cmd.ProcessState)
- bye.Cmd.Process.Release()
- time.Sleep(time.Second * 3)
- CMD = _fork(env)
- err = CMD.Start()
- if err != nil {
- fmt.Printf("[Daemon pid=%d]failed to start app process: %s\n", selfPid, err)
- return
- } else {
- fmt.Printf("[Daemon pid=%d]succeed start app process, pid=%d\n", selfPid, CMD.Process.Pid)
- }
- go func() {
- err := CMD.Wait()
- item := Bye{
- Cmd: CMD,
- Error: err,
- }
- done <- item
- }()
- }
- }
- ForEnd:
- fmt.Printf("[Daemon pid=%s]daemon process exiting...\n", selfPid)
- }
守护进程
来源: http://www.bubuko.com/infodetail-3825817.html