golang进程启动及监控

1 golang进程启动及监控

文章目录

  • 1 golang进程启动及监控
    • 1.1 以集成到业务代码的方式实现
    • 1.2 以单独代码的方式实现

以前用c++写过进程守护程序,可启动任意进程并监控进程,如果进程退出就自动重启,这里涉及到两个功能:

  • 守护进程(deamon):为任意进程创建守护进程,使进程脱离终端运行
  • 监控进程(forever):创建监控重启进程,使进程被杀死后能够重启

由于近期项目需要,使用go预研开发边缘智能程序,因此就想着通过golang实现进程守护及进程监控的功能,在golang程序中启动子进程,有很好的封装exec.Command,导入包为os/exec,本文主要以此种方式实现,包含以下两种实现方式。

1.1 以集成到业务代码的方式实现

此方式是把相关代码集成到我们需要监控的进程代码中,通过命令行参数来判断是否启用守护进程,其代码如下所示:
test.go

package test

import (
 "flag"
 "fmt"
 "os"
 "os/exec"
 "time"
)
func main() {
 daemon := flag.Bool("deamon", false, "run in daemon and forever")
 flag.Parse()
 //判断是否以守护进程的方式启动
 if *daemon {
  runbydeamon(os.Args) //执行deamon,由其启动主程序
 }
 //业务主程序代码
 fmt.Println("start test Service")
}

//以deamon的方式启动程序,并监控进程
func runbydeamon(args []string) {
 fmt.Printf("PID: %d PPID: %d ARG: %s\n", os.Getpid(), os.Getppid(), os.Args)
 //去掉-deamon运行参数,启动主程序
 for i := 0; i < len(args); {
  if args[i] == "-deamon" && i != len(args)-1 {
   args = append(args[:i], args[i+1:]...)
  } else if args[i] == "-deamon" && i == len(args)-1 {
   args = args[:i]
  } else {
   i++
  }
 }
 //启动子进程,去掉-deamon参数后,执行程序,由于子程序无deamon参数,因此会直接执行业务代码
 for {
  cmd := exec.Command(args[0], args[1:]...)
  cmd.Stdin = os.Stdin
  cmd.Stdout = os.Stdout
  cmd.Stderr = os.Stderr
  err := cmd.Start()//开启子进程
  if err != nil {
   fmt.Fprintf(os.Stderr, "start oasis erir [-] Error: %s\n", err)
   return
  }
  fmt.Println("run oasis bydeamon,pid=", cmd.Process.Pid, ",ppid=", os.Getpid(), "args=", args, "time=", time.Now())
  cmd.Wait() //阻塞等待进程退出
 }
}

通过go buid编写以后,执行"test -deamon"后,由于带有代码会启动两个test进程,第一次启动时由于带有参数"-deamon",因此会调用runbydeamon,此函数会去掉-deamon参数,再次以子进程的方式执行"test",通过cmd.start()启动子进程,子进程由于不带"-deamon",会直接进入业务代码实现,这里会打印:
start test Service,守护进程有一个for循环,一直在等待子进程退出,如果子进程异常退出,守护进程会再次把子进程进程拉起来并等待。

1.2 以单独代码的方式实现

上文实现方式,与业务代码耦合,启动时只需要带有一个参数即可启动守护进程和业务进程,启动比较简单,但是代码与业务耦合在一起,这种写法使得没法复用守护进程,其实守护进程与业务进程没有任何关系,大可提取出来,作为通用的守护进程程序,支持任务进程的后台启动和监控,代码如下:
deamon.go

package deamon

import (
 "flag"
 "fmt"
 "os"
 "os/exec"
 "time"
)
func main() {
 pcmd := flag.String("cmd", "", "run cmd in daemon and forever")
 flag.Parse()
 runbydeamon(*pcmd) //执行deamon,由其启动主程序
}

//以deamon的方式启动程序,并监控进程
func runbydeamon(args string) {
 fmt.Printf("PID: %d PPID: %d ARG: %s\n", os.Getpid(), os.Getppid(), os.Args)
 if cmd==""{
    fmt.Println("cmd is null")
    os.Exit(0)
 }
 //启动子进程,既是去掉-deamon参数后,执行程序,由于子程序无deamon参数,因此会直接执行业务代码
 for {
  cmd := exec.Command(args[1], args[2:]...)
  cmd.Stdin = os.Stdin
  cmd.Stdout = os.Stdout
  cmd.Stderr = os.Stderr
  err := cmd.Start()//开启子进程
  if err != nil {
   fmt.Fprintf(os.Stderr, "start oasis erir [-] Error: %s\n", err)
   return
  }
  fmt.Println("run oasis bydeamon,pid=", cmd.Process.Pid, ",ppid=", os.Getpid(), "args=", args, "time=", time.Now())
  cmd.Wait() //阻塞等待进程退出
 }
}

test.go

package test
import (
 "flag"
 "fmt"
)
func main() {
   fmt.Println("start test Service") 
}

以守护进程的方式启动进程命令:
deamon -cmd “test”

如果执行test要带命令行,可直接作为deamon的命令行传递给test:
deamon -cmd “test” -c “config.yaml”

有关运行参数flag定义,可根据需要自行定义,这里仅是一个例子

你可能感兴趣的:(golang,golang,deamon,守护进程,进程监控)