2017-04-26 2 views
0

Je construis un serveur en Go en utilisant la bibliothèque multiplexeur gorilla trouvée dans https://github.com/gorilla/mux. Le problème est que je veux l'éteindre gracieusement quand j'utilise Ctrl + C, ou quand il y a un appel d'API spécifique, par exemple "/ shutdown".Gracieusement Shutdown Gorilla Server

Je sais déjà que dans Go 1.8, la fermeture progressive est déjà implémentée. Mais comment le combiner avec le multiplexeur Gorilla? Aussi, comment le combiner avec le signal SIGINT?

Quelqu'un peut-il me montrer comment le faire?

Répondre

4

Le canal peut être utilisé pour capturer la demande d'arrêt via l'appel API (/shutdown) ou le signal d'interruption (Ctrl+C).

  1. Intégrer http.Server dans un struct personnalisé, afin que nous puissions appeler http Server.Shutdown plus tard
  2. Ajouter un champ de canal (shutdownReq) pour faire passer la demande d'arrêt de l'appel API /shutdown
  3. Enregistrer les gestionnaires http y compris /shutdown dans le routeur de gorilla/mux, puis attribuez-lui le routeur à http.Server.Handler
  4. registre os.Interrupt/syscall.SIGINT, syscall.SIGTERM gestionnaire
  5. Utilisez select pour capturer SHUTD propre demande par appel API ou interrupt signaux
  6. Effectuer arrêt propre en appelant Server.Shutdown

Voici l'exemple de 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!\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!") 
} 

Remarque: S'il vous plaît regarder this issue qui est liée à Gracefull arrêt.