douer9399 2017-04-26 10:39
浏览 61
已采纳

正常关闭大猩猩服务器

I'm building a server in go using gorilla multiplexer library found in https://github.com/gorilla/mux. The problem is, I want it to gracefully shutdown when I'm using Ctrl+C, or when there is a specific API call, for example "/shutdown".

I already know that in Go 1.8, graceful shutdown is already implemented. But how to combine it with gorilla multiplexer? Also, how to combine it with SIGINT signal?

Can anyone show me how to do it?

  • 写回答

1条回答 默认 最新

  • douxuanwei1980 2017-04-26 16:19
    关注

    Channel can be used to capture shutdown request through API call (/shutdown) or interrupt signal (Ctrl+C).

    1. Embed http.Server into a custom struct, so we can call http Server.Shutdown later
    2. Add channel field (shutdownReq) for passing shutdown request from API call /shutdown
    3. Register http handlers including /shutdown in gorilla/mux's router, then assign the router to http.Server.Handler
    4. Register os.Interrupt/syscall.SIGINT, syscall.SIGTERM handler
    5. Use select to capture shutdown request through API call or interrupt signal
    6. Perform clean shutdown by calling Server.Shutdown

    Below is the example code:

    package main
    
    import (
        "context"
        "log"
        "net/http"
        "sync/atomic"
        "syscall"
        "time"
    
        "os"
        "os/signal"
    
        "github.com/gorilla/mux"
    )
    
    type myServer struct {
        http.Server
        shutdownReq chan bool
        reqCount    uint32
    }
    
    func NewServer() *myServer {
        //create server
        s := &myServer{
            Server: http.Server{
                Addr:         ":8080",
                ReadTimeout:  10 * time.Second,
                WriteTimeout: 10 * time.Second,
            },
            shutdownReq: make(chan bool),
        }
    
        router := mux.NewRouter()
    
        //register handlers
        router.HandleFunc("/", s.RootHandler)
        router.HandleFunc("/shutdown", s.ShutdownHandler)
    
        //set http server handler
        s.Handler = router
    
        return s
    }
    
    func (s *myServer) WaitShutdown() {
        irqSig := make(chan os.Signal, 1)
        signal.Notify(irqSig, syscall.SIGINT, syscall.SIGTERM)
    
        //Wait interrupt or shutdown request through /shutdown
        select {
        case sig := <-irqSig:
            log.Printf("Shutdown request (signal: %v)", sig)
        case sig := <-s.shutdownReq:
            log.Printf("Shutdown request (/shutdown %v)", sig)
        }
    
        log.Printf("Stoping http server ...")
    
        //Create shutdown context with 10 second timeout
        ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
        defer cancel()
    
        //shutdown the server
        err := s.Shutdown(ctx)
        if err != nil {
            log.Printf("Shutdown request error: %v", err)
        }
    }
    
    func (s *myServer) RootHandler(w http.ResponseWriter, r *http.Request) {
        w.Write([]byte("Hello Gorilla MUX!
    "))
    }
    
    func (s *myServer) ShutdownHandler(w http.ResponseWriter, r *http.Request) {
        w.Write([]byte("Shutdown server"))
    
        //Do nothing if shutdown request already issued
        //if s.reqCount == 0 then set to 1, return true otherwise false
        if !atomic.CompareAndSwapUint32(&s.reqCount, 0, 1) {
            log.Printf("Shutdown through API call in progress...")
            return
        }
    
        go func() {
            s.shutdownReq <- true
        }()
    }
    
    func main() {
        //Start the server
        server := NewServer()
    
        done := make(chan bool)
        go func() {
            err := server.ListenAndServe()
            if err != nil {
                log.Printf("Listen and serve: %v", err)
            }
            done <- true
        }()
    
        //wait shutdown
        server.WaitShutdown()
    
        <-done
        log.Printf("DONE!")
    }
    

    Note: Please watch this issue which is related to gracefull shutdown.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 程序不包含适用于入口点的静态Main方法
  • ¥15 素材场景中光线烘焙后灯光失效
  • ¥15 请教一下各位,为什么我这个没有实现模拟点击
  • ¥15 执行 virtuoso 命令后,界面没有,cadence 启动不起来
  • ¥50 comfyui下连接animatediff节点生成视频质量非常差的原因
  • ¥20 有关区间dp的问题求解
  • ¥15 多电路系统共用电源的串扰问题
  • ¥15 slam rangenet++配置
  • ¥15 有没有研究水声通信方面的帮我改俩matlab代码
  • ¥15 ubuntu子系统密码忘记