exec go 重启_golang平滑重启

背景:

更新配置文件、更新server程序等,需要重启服务器,需要做到重启服务器时,服务器不停止运行,请求不丢失

原理:

热重启原理涉及到一些系统调用及父子进程之间文件句柄的传递等较多细节,处理过程大致如下:

监听信号

收到 kill -1 信号时, fork子进程(使用相同的启动命令),将文件描述符、环境参数等传递给子进程

这时父进程、子进程同时存在

子进程启动后,父进程停止执行服务,停止接受请求,父进程等到旧链接、业务处理完成(或超时)

父进程退出,重启完成

serve.go

package goo

import (

"fmt"

"log"

"os"

"os/signal"

"syscall"

)

type Serve struct {

ShutDown bool

ChanSignal chan os.Signal

}

func NewServe() *Serve {

c := make(chan os.Signal)

signal.Notify(c)

serve := Serve{

ChanSignal: c,

}

serve.pid()

go serve.run()

return &serve

}

func (this *Serve) run() {

for s := range this.ChanSignal {

switch s {

case syscall.SIGHUP:

execSpec := &syscall.ProcAttr{

Env: os.Environ(),

Files: []uintptr{os.Stdin.Fd(), os.Stdout.Fd(), os.Stderr.Fd()},

}

if _, err := syscall.ForkExec(os.Args[0], os.Args, execSpec); err != nil {

log.Fatalln(err.Error())

}

this.ShutDown = true

signal.Stop(this.ChanSignal)

case syscall.SIGKILL, syscall.SIGINT:

this.ShutDown = true

signal.Stop(this.ChanSignal)

}

}

}

func (this *Serve) pid() error {

file, err := os.Create(".pid")

if err != nil {

return err

}

defer file.Close()

file.WriteString(fmt.Sprintf("%d", os.Getpid()))

return nil

}

func (this *Serve) Stop() {

os.Exit(0)

}

main.go

package main

import (

"fmt"

"time"

"googo.co/goo"

)

var (

serve *goo.Serve

)

func init() {

serve = goo.NewServe()

}

func main() {

num := 0

c := make(chan string)

for {

num = num + 1

go SyncArticle(c)

for {

msg :=

if msg == "end" {

if serve.ShutDown {

serve.Stop()

}

time.Sleep(time.Duration(config.IDataApi.Time) * time.Minute)

break

}

fmt.Println(time.Now().Format("2006-01-02 15:04:05"), num, msg)

}

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值