优雅地关闭 Gorilla 服务器
Gracefully Shutdown Gorilla Server
我正在使用 https://github.com/gorilla/mux 中的大猩猩多路复用器库构建一个服务器。
问题是,我希望它在我使用 Ctrl+C 时正常关闭,或者在有特定的 API 调用时正常关闭,例如“/shutdown”。
我已经知道Go 1.8已经实现了优雅关机。但是如何将它与大猩猩多路复用器结合起来呢?另外,如何结合SIGINT信号?
谁能告诉我怎么做?
通道可用于通过API调用(/shutdown
)或中断信号(Ctrl+C
)捕获关闭请求。
- 将
http.Server
嵌入到自定义结构中,以便稍后调用 http Server.Shutdown
- 添加通道字段 (
shutdownReq
) 以传递来自 API 调用 /shutdown
的关闭请求
- 在
gorilla/mux
的路由器中注册包括 /shutdown
的 http 处理程序,然后将路由器分配给 http.Server.Handler
- 注册
os.Interrupt/syscall.SIGINT, syscall.SIGTERM
处理程序
- 使用
select
通过API调用或interrupt
信号捕获关机请求
- 通过调用
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与正常关机相关的内容。
我正在使用 https://github.com/gorilla/mux 中的大猩猩多路复用器库构建一个服务器。 问题是,我希望它在我使用 Ctrl+C 时正常关闭,或者在有特定的 API 调用时正常关闭,例如“/shutdown”。
我已经知道Go 1.8已经实现了优雅关机。但是如何将它与大猩猩多路复用器结合起来呢?另外,如何结合SIGINT信号?
谁能告诉我怎么做?
通道可用于通过API调用(/shutdown
)或中断信号(Ctrl+C
)捕获关闭请求。
- 将
http.Server
嵌入到自定义结构中,以便稍后调用 http Server.Shutdown - 添加通道字段 (
shutdownReq
) 以传递来自 API 调用/shutdown
的关闭请求
- 在
gorilla/mux
的路由器中注册包括/shutdown
的 http 处理程序,然后将路由器分配给http.Server.Handler
- 注册
os.Interrupt/syscall.SIGINT, syscall.SIGTERM
处理程序 - 使用
select
通过API调用或interrupt
信号捕获关机请求 - 通过调用
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与正常关机相关的内容。