I want to gracefull restart golang server.I
listen a fd in master process, fork a child process inherit the fd and
only the child accept connection.When i restart, I want to firstly fork
new master process and child process which inherit the listen fd from
old master’s listen fd.Do this, in any time listen port is alive. And
why two processes alive: I want to master monitor child, if child
process crash, master process can start a new child process inmediately.
some code:
var parent_flag = flag.Bool("P", false, "Parent Watch Mode")
var fork_flag = flag.Bool("F", false, "Process forked")
var msgListenFd uintptr
var rpcListenFd uintptr
func InitListener() {
//conf load
conf.LoadConf()
msgOpts := conf.GetMsgServiceOpts()
msgsrv.ListenNotServe(msgOpts.ListenAddr)
msgListenFd = msgsrv.GetListenFd()
logger.Errorf(nil, "msgListenFd:%v", msgListenFd)
rpcServiceOpts := conf.GetRpcServiceOpts()
rpcsrv.ListenNotServe(rpcServiceOpts.ListenAddr)
rpcListenFd = rpcsrv.GetListenFd()
logger.Errorf(nil, "rpcListenFd:%v", rpcListenFd)
}
func InitListenerInGraceful() {
msgsrv.ListenWithFork(3)
rpcsrv.ListenWithFork(4)
}
func StartServe() {
msgsrv.StartServe()
rpcsrv.StartServe()
}
func main() {
if *fork_flag {
InitListenerInGraceful()
} else {
InitListener()
}
go ParentSignalMonitor()
var failCount int = 0
for {
var proc_attr syscall.ProcAttr
var sys_attr syscall.SysProcAttr
var waitStatus syscall.WaitStatus
tNow := time.Now()
stdErrFileName := fmt.Sprintf("logs/cgc.log.%04d%02d%02d%02d%02d%02d", tNow.Year(),
tNow.Month(), tNow.Day(), tNow.Hour(), tNow.Minute(), tNow.Second())
stdErrFile, err := os.OpenFile(stdErrFileName, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
//if err != nil {
logger.Errorf(nil, "os.OpenFile,err:%v", err)
//}
sys_attr.Ptrace = false
proc_attr.Sys = &sys_attr
proc_attr.Files = []uintptr{uintptr(syscall.Stdin), uintptr(syscall.Stdout), stdErrFile.Fd(), msgListenFd, rpcListenFd}
proc_attr.Env = os.Environ()
pid, err := syscall.ForkExec(os.Args[0], append(append(os.Args[0:i], os.Args[i+1:]...), "-F"), &proc_attr)
pid2, err2 := syscall.ForkExec(os.Args[0], append(append(os.Args[0:i], os.Args[i+1:]...), "-F"), &proc_attr)
os.Exit(0)
childPid = pid
//if err != nil {
logger.Errorf(nil, "syscall.ForkExec:err:%v", err)
logger.Errorf(nil, "syscall.ForkExec:err:%v,%v", err2, pid2)
//}
//fmt.Printf("syscall.ForkExec:err:%v", err)
syscall.Wait4(pid, &waitStatus, 0, nil)
if time.Now().Sub(tNow).Seconds() < float64(30) {
failCount++
} else {
failCount = 0
}
if failCount > 5 {
logger.Errorf(nil, "Parent process exited. failCount > 5")
//quit
return
}
if stopping {
logger.Errorf(nil, "Parent process exited.")
return
}
}
} else {
if *fork_flag {
InitListenerInGraceful()
} else {
logger.Warningf(nil, "InitListener...")
InitListener()
}
err := Init()
if err != nil {
logger.Fatal(nil, err)
}
if *fork_flag {
ppid := os.Getppid()
syscall.Kill(ppid, syscall.SIGUSR1)
} else {
StartServe()
}
SignalMonitor()
Stop()
}
}