• golang进程启动及监控


    1 golang进程启动及监控


    以前用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() //阻塞等待进程退出
     }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49

    通过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() //阻塞等待进程退出
     }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    test.go

    package test
    import (
     "flag"
     "fmt"
    )
    func main() {
       fmt.Println("start test Service") 
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

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

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

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

  • 相关阅读:
    java毕业设计糖助手服务交流平台mybatis+源码+调试部署+系统+数据库+lw
    JavaWeb开发之——数据库相关概念(02)
    【后端开发实习】用Nodejs操作mongodb结合Mongoose实现数据库操作
    微信小程序开发学习5(自定义组件)
    2024年华为OD机试真题-生成哈夫曼树-Java-OD统一考试(C卷)
    Android NDK篇-C++语言之 this 原理和可变参数与友元函数友元类
    注解@PostConstruct分析
    二分查找 binarySearch 适合初学分析的例子
    Github最新霸榜,Alibaba架构师手写的分布式系统核心原理手册
    react | react-router-dom v6 结合 antd 面包屑 |嵌套路由
  • 原文地址:https://blog.csdn.net/water1209/article/details/126639949