2017-04-26 21 views
0

https://github.com/gorilla/mux에있는 고릴라 멀티플렉서 라이브러리를 사용하여 이동 중에 서버를 구축하고 있습니다. 문제는 Ctrl + C를 사용하거나 특정 API 호출 (예 : "/ shutdown")이있을 때 정상적으로 종료되도록하려는 것입니다.Gracefully Gorilla Server 종료

Go 1.8에서는 정상적인 종료가 이미 구현되었음을 알고 있습니다. 그러나 이것을 고릴라 멀티플렉서와 ​​결합하는 방법은 무엇입니까? 또한 SIGINT 신호와 결합하는 방법은 무엇입니까?

아무에게도 어떻게 할 수 있습니까?

답변

4

채널은 API 호출 (/shutdown) 또는 인터럽트 신호 (Ctrl+C)를 통해 종료 요청을 캡처하는 데 사용할 수 있습니다.

사용자 정의 구조체에
  1. 삽입 http.Server , 그래서 우리는 호출 할 수 있습니다 http Server.Shutdown 나중에
  2. API 호출에서 gorilla/mux의 라우터 /shutdown 포함 /shutdown
  3. 등록 HTTP 처리기를 종료 요청을 전달하는 채널 필드 (shutdownReq)를 추가, 다음 http.Server.Handler
  4. 등록 shutd을 캡처 os.Interrupt/syscall.SIGINT, syscall.SIGTERM 핸들러
  5. 사용 select에 라우터를 할당

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

    : API 호출 또는 interrupt 신호를 통해 자신의 요청이

  6. Server.Shutdown

를 호출하여 완전 종료를 수행 아래 예제 코드 종료를 gracefull 관련이 this issue을 봐주세요.