• 企业400电话
  • 微网小程序
  • AI电话机器人
  • 电商代运营
  • 全 部 栏 目

    企业400电话 网络优化推广 AI电话机器人 呼叫中心 网站建设 商标✡知产 微网小程序 电商运营 彩铃•短信 增值拓展业务
    golang 监听服务的信号,实现平滑启动,linux信号说明详解

    监听服务的信号,实现平滑启动,linux信号说明

    package main 
    import (
    	"context"
    	"fmt"
    	"golang.org/x/sync/errgroup"
    	"net/http"
    	"os"
    	"os/signal"
    	"syscall"
    ) 
     
    func main() { 
    	g, ctx := errgroup.WithContext(context.Background())
    	fmt.Println("服务启动start!")
    	addr := ":9091"
    	s :=http.Server{
    		Addr: addr,
    		Handler:http.DefaultServeMux,
    	}
    	g.Go(func() error {
    		http.HandleFunc("/test1", func(writer http.ResponseWriter, request *http.Request) {
    			fmt.Println("tes1")
    			writer.Write([]byte("tes1"))
    		})
    		return s.ListenAndServe()
    	})
    	g.Go(func() error {
    		exit := make(chan os.Signal)
    		//监听 Ctrl+C 信号
    		signal.Notify(exit, syscall.SIGINT, syscall.SIGTERM)
    		select {
    		case -exit:
    			fmt.Println("进程已被取消~")
    			return s.Shutdown(ctx)
    		}
    	})
    	err := g.Wait()
    	if err != nil {
    		fmt.Println(err)
    	}
    	fmt.Println("服务启动成功!")
    	if ctx.Err() !=nil {
    		fmt.Println(ctx.Err())
    		fmt.Println("服务关闭成功!")
    		os.Exit(0)
    	}
     
    }

    补充:golang http服务实现平滑重启

    看代码吧~

    package main 
    import (
        "context"
        "encoding/json"
        "fmt"
        "math/rand"
        "net/http"
        "os"
        "os/signal"
        "time"
    )
     
    var logChan  = make(chan map[string]interface{}) 
    var requestStatusMap = map[int]bool{}  
    var done = make(chan bool, 1)
    var quit = make(chan os.Signal, 1) 
     
    //为什么这样可以平滑重启?
    // 正常情况下是server.ListenAndServe() 这个位置hang住整个进程的
    // 可以把这个程序看成两部分,1个是web服务的监听部分,一个是处理部分, 如果web服务器不开启了,那么就不能处理新进来的请求了(可以理解为一个带路的)
    // 真正让这个请求断掉  是因为主进程(main)被kill
    // 所以平滑重启的原理就是,先kill掉web服务器,不让新的请求进来,等现有的全部请求完了,然后结束当前进程
    func main() {
        server := newServer()
        signal.Notify(quit, os.Interrupt)
        go monitorKill(server, quit)
        server.ListenAndServe()
        -done
    } 
     
    func newServer() *http.Server {
        router := http.NewServeMux()
        router.HandleFunc("/hello", sayHello)
        return http.Server{
            Addr:         ":8262",
            Handler:      router,
        }
    }
     
    func monitorKill(server *http.Server, quit -chan os.Signal)  {
        -quit
        go shutDown(server)
        for {
            if len(requestStatusMap) != 0 {
                fmt.Println("目前还有进行中的请求,请稍等")
                time.Sleep(time.Second * 1)
                continue
            } else {
                close(done)
                break
            }
        }
    }
     
    func shutDown(server *http.Server) {
        if err := server.Shutdown(context.Background()); err != nil {
            fmt.Println(err)
        }
    }
     
    func sayHello(w http.ResponseWriter, r *http.Request) {
        go WriteInfo()//请求写日志
        var uniqueId = GenerateRangeNum(1, 1000)
        requestStatusMap[uniqueId] = false
        url := r.URL.Path
        query  := r.URL.RawQuery
        method := r.Method
        a := map[string] interface{}{
            "url" : url,
            "method" : method,
            "query" : query,
            "response": "hello world!",
        }
        logChan-a
        w.Write([]byte("hello world!"))
        time.Sleep(time.Second * 10)
        delete(requestStatusMap, uniqueId)
    }
     
    func WriteInfo() {
        info := -logChan
        fileName := "/tmp/weekhomework.log"
        _, err := os.Stat(fileName)
        if err != nil || os.IsNotExist(err) {
            _, _ = os.Create(fileName)
        }
        f,err := os.OpenFile(fileName, os.O_WRONLY, 0644)
        defer f.Close()
        if err !=nil {
            fmt.Println(err.Error())
        } else {
            //追加写入   为什么O_APPEND 模式无法写入? todo
            n, _ := f.Seek(0, 2)
            infostr, _ := json.Marshal(info)
            _,err=f.WriteAt([]byte(string(infostr) +"\n"), n)
        }
    }
     
    func GenerateRangeNum(min int, max int) int {
        if min == max {
            return min
        }
        rand.Seed(time.Now().Unix())
        randNum := rand.Intn(max-min) + min
        return randNum
    }

    主要思路:

    对于每个请求都做记录,处理完成之后做删除。 用一个协程去监控中断信号,有中断信号先把http服务关闭。

    如果这个时候还有请求没有处理完,那么就轮训等待,等全部处理完那么就 发出终止信号结束main进程的执行

    以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。如有错误或未考虑完全的地方,望不吝赐教。

    您可能感兴趣的文章:
    • Linux进程间通信--使用信号
    • 详解Linux进程间通信——使用信号量
    • 详解Linux多线程使用信号量同步
    • Linux下的信号详解及捕捉信号
    • linux下基于C语言的信号编程实例
    • Linux线程同步之信号C语言实例
    • linux多线程编程详解教程(线程通过信号量实现通信代码)
    • Linux下semop等待信号时出现Interrupted System Call错误(EINTR)解决方法
    • 浅谈Linux信号机制
    上一篇:GO语言ini配置文件的读取的操作
    下一篇:golang值类型转换成[]uint8类型的操作
  • 相关文章
  • 

    © 2016-2020 巨人网络通讯 版权所有

    《增值电信业务经营许可证》 苏ICP备15040257号-8

    golang 监听服务的信号,实现平滑启动,linux信号说明详解 golang,监听,服务,的,信号,