167 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			167 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // Copyright 2014 beego Author. All Rights Reserved.
 | |
| //
 | |
| // Licensed under the Apache License, Version 2.0 (the "License");
 | |
| // you may not use this file except in compliance with the License.
 | |
| // You may obtain a copy of the License at
 | |
| //
 | |
| //      http://www.apache.org/licenses/LICENSE-2.0
 | |
| //
 | |
| // Unless required by applicable law or agreed to in writing, software
 | |
| // distributed under the License is distributed on an "AS IS" BASIS,
 | |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | |
| // See the License for the specific language governing permissions and
 | |
| // limitations under the License.
 | |
| 
 | |
| // Package grace use to hot reload
 | |
| // Description: http://grisha.org/blog/2014/06/03/graceful-restart-in-golang/
 | |
| //
 | |
| // Usage:
 | |
| //
 | |
| // import(
 | |
| //   "log"
 | |
| //	 "net/http"
 | |
| //	 "os"
 | |
| //
 | |
| //   "github.com/astaxie/beego/grace"
 | |
| // )
 | |
| //
 | |
| //  func handler(w http.ResponseWriter, r *http.Request) {
 | |
| //	  w.Write([]byte("WORLD!"))
 | |
| //  }
 | |
| //
 | |
| //  func main() {
 | |
| //      mux := http.NewServeMux()
 | |
| //      mux.HandleFunc("/hello", handler)
 | |
| //
 | |
| //	    err := grace.ListenAndServe("localhost:8080", mux)
 | |
| //      if err != nil {
 | |
| //		   log.Println(err)
 | |
| //	    }
 | |
| //      log.Println("Server on 8080 stopped")
 | |
| //	     os.Exit(0)
 | |
| //    }
 | |
| package grace
 | |
| 
 | |
| import (
 | |
| 	"flag"
 | |
| 	"net/http"
 | |
| 	"os"
 | |
| 	"strings"
 | |
| 	"sync"
 | |
| 	"syscall"
 | |
| 	"time"
 | |
| )
 | |
| 
 | |
| const (
 | |
| 	// PreSignal is the position to add filter before signal
 | |
| 	PreSignal = iota
 | |
| 	// PostSignal is the position to add filter after signal
 | |
| 	PostSignal
 | |
| 	// StateInit represent the application inited
 | |
| 	StateInit
 | |
| 	// StateRunning represent the application is running
 | |
| 	StateRunning
 | |
| 	// StateShuttingDown represent the application is shutting down
 | |
| 	StateShuttingDown
 | |
| 	// StateTerminate represent the application is killed
 | |
| 	StateTerminate
 | |
| )
 | |
| 
 | |
| var (
 | |
| 	regLock              *sync.Mutex
 | |
| 	runningServers       map[string]*Server
 | |
| 	runningServersOrder  []string
 | |
| 	socketPtrOffsetMap   map[string]uint
 | |
| 	runningServersForked bool
 | |
| 
 | |
| 	// DefaultReadTimeOut is the HTTP read timeout
 | |
| 	DefaultReadTimeOut time.Duration
 | |
| 	// DefaultWriteTimeOut is the HTTP Write timeout
 | |
| 	DefaultWriteTimeOut time.Duration
 | |
| 	// DefaultMaxHeaderBytes is the Max HTTP Header size, default is 0, no limit
 | |
| 	DefaultMaxHeaderBytes int
 | |
| 	// DefaultTimeout is the shutdown server's timeout. default is 60s
 | |
| 	DefaultTimeout = 60 * time.Second
 | |
| 
 | |
| 	isChild     bool
 | |
| 	socketOrder string
 | |
| 
 | |
| 	hookableSignals []os.Signal
 | |
| )
 | |
| 
 | |
| func init() {
 | |
| 	flag.BoolVar(&isChild, "graceful", false, "listen on open fd (after forking)")
 | |
| 	flag.StringVar(&socketOrder, "socketorder", "", "previous initialization order - used when more than one listener was started")
 | |
| 
 | |
| 	regLock = &sync.Mutex{}
 | |
| 	runningServers = make(map[string]*Server)
 | |
| 	runningServersOrder = []string{}
 | |
| 	socketPtrOffsetMap = make(map[string]uint)
 | |
| 
 | |
| 	hookableSignals = []os.Signal{
 | |
| 		syscall.SIGHUP,
 | |
| 		syscall.SIGINT,
 | |
| 		syscall.SIGTERM,
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // NewServer returns a new graceServer.
 | |
| func NewServer(addr string, handler http.Handler) (srv *Server) {
 | |
| 	regLock.Lock()
 | |
| 	defer regLock.Unlock()
 | |
| 
 | |
| 	if !flag.Parsed() {
 | |
| 		flag.Parse()
 | |
| 	}
 | |
| 	if len(socketOrder) > 0 {
 | |
| 		for i, addr := range strings.Split(socketOrder, ",") {
 | |
| 			socketPtrOffsetMap[addr] = uint(i)
 | |
| 		}
 | |
| 	} else {
 | |
| 		socketPtrOffsetMap[addr] = uint(len(runningServersOrder))
 | |
| 	}
 | |
| 
 | |
| 	srv = &Server{
 | |
| 		sigChan: make(chan os.Signal),
 | |
| 		isChild: isChild,
 | |
| 		SignalHooks: map[int]map[os.Signal][]func(){
 | |
| 			PreSignal: {
 | |
| 				syscall.SIGHUP:  {},
 | |
| 				syscall.SIGINT:  {},
 | |
| 				syscall.SIGTERM: {},
 | |
| 			},
 | |
| 			PostSignal: {
 | |
| 				syscall.SIGHUP:  {},
 | |
| 				syscall.SIGINT:  {},
 | |
| 				syscall.SIGTERM: {},
 | |
| 			},
 | |
| 		},
 | |
| 		state:        StateInit,
 | |
| 		Network:      "tcp",
 | |
| 		terminalChan: make(chan error), //no cache channel
 | |
| 	}
 | |
| 	srv.Server = &http.Server{
 | |
| 		Addr:           addr,
 | |
| 		ReadTimeout:    DefaultReadTimeOut,
 | |
| 		WriteTimeout:   DefaultWriteTimeOut,
 | |
| 		MaxHeaderBytes: DefaultMaxHeaderBytes,
 | |
| 		Handler:        handler,
 | |
| 	}
 | |
| 
 | |
| 	runningServersOrder = append(runningServersOrder, addr)
 | |
| 	runningServers[addr] = srv
 | |
| 	return srv
 | |
| }
 | |
| 
 | |
| // ListenAndServe refer http.ListenAndServe
 | |
| func ListenAndServe(addr string, handler http.Handler) error {
 | |
| 	server := NewServer(addr, handler)
 | |
| 	return server.ListenAndServe()
 | |
| }
 | |
| 
 | |
| // ListenAndServeTLS refer http.ListenAndServeTLS
 | |
| func ListenAndServeTLS(addr string, certFile string, keyFile string, handler http.Handler) error {
 | |
| 	server := NewServer(addr, handler)
 | |
| 	return server.ListenAndServeTLS(certFile, keyFile)
 | |
| }
 |