mirror of
https://github.com/jhillyerd/inbucket.git
synced 2025-12-18 01:57:02 +00:00
Basic SIGTERM handling
This commit is contained in:
17
inbucket.go
17
inbucket.go
@@ -29,6 +29,8 @@ var startTime = time.Now()
|
||||
// The file we send log output to, will be nil for stderr or stdout
|
||||
var logf *os.File
|
||||
|
||||
var smtpServer *smtpd.Server
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
if *help {
|
||||
@@ -49,7 +51,7 @@ func main() {
|
||||
|
||||
// Setup signal handler
|
||||
sigChan := make(chan os.Signal)
|
||||
signal.Notify(sigChan, syscall.SIGHUP)
|
||||
signal.Notify(sigChan, syscall.SIGHUP, syscall.SIGTERM)
|
||||
go signalProcessor(sigChan)
|
||||
|
||||
// Configure logging, close std* fds
|
||||
@@ -91,8 +93,8 @@ func main() {
|
||||
}
|
||||
|
||||
// Startup SMTP server
|
||||
server := smtpd.New()
|
||||
go server.Start()
|
||||
smtpServer = smtpd.New()
|
||||
go smtpServer.Start()
|
||||
|
||||
web.Start()
|
||||
}
|
||||
@@ -130,6 +132,15 @@ func signalProcessor(c <-chan os.Signal) {
|
||||
} else {
|
||||
log.Info("Ignoring SIGHUP, logfile not configured")
|
||||
}
|
||||
case syscall.SIGTERM:
|
||||
// Initiate shutdown
|
||||
log.Info("Received SIGTERM, shutting down")
|
||||
if smtpServer != nil {
|
||||
smtpServer.Stop()
|
||||
} else {
|
||||
log.Error("smtpServer was nil during shutdown")
|
||||
}
|
||||
web.Stop()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,8 @@ type Server struct {
|
||||
maxMessageBytes int
|
||||
dataStore DataStore
|
||||
storeMessages bool
|
||||
listener net.Listener
|
||||
shutdown bool
|
||||
}
|
||||
|
||||
// Raw stat collectors
|
||||
@@ -62,9 +64,9 @@ func (s *Server) Start() {
|
||||
}
|
||||
|
||||
log.Info("SMTP listening on TCP4 %v", addr)
|
||||
ln, err := net.ListenTCP("tcp4", addr)
|
||||
s.listener, err = net.ListenTCP("tcp4", addr)
|
||||
if err != nil {
|
||||
log.Error("Failed to start tcp4 listener: %v", err)
|
||||
log.Error("SMTP failed to start tcp4 listener: %v", err)
|
||||
// TODO More graceful early-shutdown procedure
|
||||
panic(err)
|
||||
}
|
||||
@@ -79,18 +81,45 @@ func (s *Server) Start() {
|
||||
StartRetentionScanner(s.dataStore)
|
||||
|
||||
// Handle incoming connections
|
||||
var tempDelay time.Duration
|
||||
for sid := 1; ; sid++ {
|
||||
if conn, err := ln.Accept(); err != nil {
|
||||
// TODO Implement a max error counter before shutdown?
|
||||
// or maybe attempt to restart smtpd
|
||||
panic(err)
|
||||
if conn, err := s.listener.Accept(); err != nil {
|
||||
if nerr, ok := err.(net.Error); ok && nerr.Temporary() {
|
||||
// Temporary error, sleep for a bit and try again
|
||||
if tempDelay == 0 {
|
||||
tempDelay = 5 * time.Millisecond
|
||||
} else {
|
||||
tempDelay *= 2
|
||||
}
|
||||
if max := 1 * time.Second; tempDelay > max {
|
||||
tempDelay = max
|
||||
}
|
||||
log.Error("SMTP accept error: %v; retrying in %v", err, tempDelay)
|
||||
time.Sleep(tempDelay)
|
||||
continue
|
||||
} else {
|
||||
if s.shutdown {
|
||||
log.Trace("SMTP listener shutting down on request")
|
||||
return
|
||||
}
|
||||
// TODO Implement a max error counter before shutdown?
|
||||
// or maybe attempt to restart smtpd
|
||||
panic(err)
|
||||
}
|
||||
} else {
|
||||
tempDelay = 0
|
||||
expConnectsTotal.Add(1)
|
||||
go s.startSession(sid, conn)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) Stop() {
|
||||
log.Trace("SMTP shutdown requested")
|
||||
s.shutdown = true
|
||||
s.listener.Close()
|
||||
}
|
||||
|
||||
// When the provided Ticker ticks, we update our metrics history
|
||||
func metricsTicker(t *time.Ticker) {
|
||||
ok := true
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"github.com/gorilla/sessions"
|
||||
"github.com/jhillyerd/inbucket/config"
|
||||
"github.com/jhillyerd/inbucket/log"
|
||||
"net"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
@@ -17,8 +18,9 @@ import (
|
||||
type handler func(http.ResponseWriter, *http.Request, *Context) error
|
||||
|
||||
var Router *mux.Router
|
||||
|
||||
var listener net.Listener
|
||||
var sessionStore sessions.Store
|
||||
var shutdown bool
|
||||
|
||||
func setupRoutes(cfg config.WebConfig) {
|
||||
log.Info("Theme templates mapped to '%v'", cfg.TemplateDir)
|
||||
@@ -55,20 +57,41 @@ func Start() {
|
||||
sessionStore = sessions.NewCookieStore([]byte("something-very-secret"))
|
||||
|
||||
addr := fmt.Sprintf("%v:%v", cfg.Ip4address, cfg.Ip4port)
|
||||
log.Info("HTTP listening on TCP4 %v", addr)
|
||||
s := &http.Server{
|
||||
server := &http.Server{
|
||||
Addr: addr,
|
||||
Handler: nil,
|
||||
ReadTimeout: 60 * time.Second,
|
||||
WriteTimeout: 60 * time.Second,
|
||||
}
|
||||
|
||||
err := s.ListenAndServe()
|
||||
// We don't use ListenAndServe because it lacks a way to close the listener
|
||||
log.Info("HTTP listening on TCP4 %v", addr)
|
||||
var err error
|
||||
listener, err = net.Listen("tcp", addr)
|
||||
if err != nil {
|
||||
log.Error("HTTP failed to start TCP4 listener: %v", err)
|
||||
// TODO More graceful early-shutdown procedure
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = server.Serve(listener)
|
||||
if shutdown {
|
||||
log.Trace("HTTP server shutting down on request")
|
||||
} else if err != nil {
|
||||
log.Error("HTTP server failed: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func Stop() {
|
||||
log.Trace("HTTP shutdown requested")
|
||||
shutdown = true
|
||||
if listener != nil {
|
||||
listener.Close()
|
||||
} else {
|
||||
log.Error("HTTP listener was nil during shutdown")
|
||||
}
|
||||
}
|
||||
|
||||
// ServeHTTP builds the context and passes onto the real handler
|
||||
func (h handler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||
// Create the context
|
||||
|
||||
Reference in New Issue
Block a user