2017-04-26 104 views
0

我正在建立一个服务器去使用在https://github.com/gorilla/mux发现的大猩猩多路复用器库。 问题是,我希望它在我使用Ctrl + C时正常关闭,或者有特定的API调用时(例如“/ shutdown”)。优雅地关闭Gorilla服务器

我已经知道在Go 1.8中,已经实现了优雅关机。但如何将它与大猩猩多路复用器相结合?另外,如何将它与SIGINT信号结合起来?

任何人都可以告诉我该怎么做吗?

回答

4

通道可用于通过API调用(/shutdown)或中断信号(Ctrl+C)捕获关闭请求。

  1. 嵌入http.Server到定制的结构,所以我们可以称之为http Server.Shutdown
  2. 频道添加字段(shutdownReq)在通过关闭请求从API调用/shutdown
  3. 注册HTTP处理程序,包括gorilla/mux的路由器/shutdown,那么路由器分配给http.Server.Handler
  4. 注册os.Interrupt/syscall.SIGINT, syscall.SIGTERM处理
  5. 使用select捕捉SHUTD通过API调用或interrupt信号对自己的要求
  6. 通过调用Server.Shutdown

执行正常关机下面是示例代码:

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!\n")) 
} 

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!") 
} 

注意:请观看this issue这是gracefull关闭有关。