pidproxy 实现
参考python的supervisor pidproxy实现
https://github.com/Supervisor/supervisor/blob/master/supervisor/pidproxy.py
子进程检查
package pidproxy
import (
"errors"
"io/ioutil"
"os"
"os/signal"
"strconv"
"strings"
"syscall"
"time"
"github.com/spf13/cobra"
)
func getPid(pidfile string) (int, error) {
dt, err := ioutil.ReadFile(pidfile)
if err != nil {
return -1, err
}
if len(dt) == 0 {
return -1, errors.New("pid is null")
}
pid, err := strconv.Atoi(string(dt))
if err != nil {
return -1, err
}
return pid, err
}
func GetCmd() *cobra.Command {
var signals = []os.Signal{
syscall.SIGHUP,
syscall.SIGUSR1,
syscall.SIGUSR2,
syscall.SIGTSTP,
syscall.SIGINT,
syscall.SIGTERM,
syscall.SIGQUIT,
syscall.SIGCHLD,
}
var sigChan = make(chan os.Signal)
var pid = -1
var pidfile = ""
var forkExec = func(argv0 string, argv []string) (pid int, err error) {
return syscall.ForkExec(argv0, argv, &syscall.ProcAttr{
Env: os.Environ(),
Files: []uintptr{os.Stdin.Fd(), os.Stdout.Fd(), os.Stderr.Fd()},
})
}
return &cobra.Command{
Use: "pp",
Short: "Run as a pidproxy server",
Example: `dio pp <pidfile name> "<command> [<cmdarg1> ...]"
dio pp test.pid "/usr/local/bin/etcd --name=default"`,
RunE: func(cmd *cobra.Command, args []string) (err error) {
if len(args) < 2 {
return errors.New("请输入pidfile和需要执行的命令以及参数")
}
if strings.TrimSpace(args[1]) == "" {
return errors.New("command命令为空")
}
command := strings.Split(args[1], " ")
pid, err = forkExec(command[0], command)
if err != nil {
return err
}
// 防止子进程变成僵尸进程
go func(pid int) {
for {
_, _ = syscall.Wait4(pid, nil, syscall.WNOWAIT, nil)
time.Sleep(time.Second * 5)
return
}
}(pid)
pidfile = args[0]
if err := ioutil.WriteFile(pidfile, []byte(strconv.Itoa(pid)), 0600); err != nil {
return err
}
signal.Notify(sigChan, signals...)
var tk = time.Tick(time.Second * 2)
var sig os.Signal
for {
select {
// pidproxy进程获取信号
case sig = <-sigChan:
// 定时监控子进程状态
case <-tk:
// 信号0一般用来检查进程是否存在, 没有具体的意义
sig = syscall.Signal(0)
}
// 获取子命令pid
if pid, err = getPid(pidfile); err != nil {
return err
}
// 校验pid是否存在
proc, err := os.FindProcess(pid)
if err != nil {
return err
}
// 给子命令发送信号, 如果程序有问题, 就退出重启
if err := proc.Signal(sig); err != nil {
return err
}
switch sig {
case syscall.SIGTERM, syscall.SIGINT, syscall.SIGQUIT:
os.Exit(0)
}
}
},
}
}
作者:百里求一
出处:http://www.cnblogs.com/bergus/
我的语雀: https://www.yuque.com/barry.bai
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

浙公网安备 33010602011771号