1
0
mirror of https://github.com/jhillyerd/inbucket.git synced 2025-12-27 06:27:04 +00:00

Use channels to communicate shutdown request

- httpd now uses shutdown channel
- smtpd now uses shutdown channel
- pop3d now uses shutdown channel
- timedExit now removes PID file
- tidy up some struct instantiations, var blocks
This commit is contained in:
James Hillyerd
2016-02-28 23:36:47 -08:00
parent 3a7be7d89c
commit 4b4121bb3a
8 changed files with 203 additions and 138 deletions

View File

@@ -17,20 +17,27 @@ type Server struct {
maxIdleSeconds int
dataStore smtpd.DataStore
listener net.Listener
shutdown bool
globalShutdown chan bool
localShutdown chan bool
waitgroup *sync.WaitGroup
}
// New creates a new Server struct
func New() *Server {
func New(shutdownChan chan bool) *Server {
// Get a new instance of the the FileDataStore - the locking and counting
// mechanisms are both global variables in the smtpd package. If that
// changes in the future, this should be modified to use the same DataStore
// instance.
ds := smtpd.DefaultFileDataStore()
cfg := config.GetPOP3Config()
return &Server{domain: cfg.Domain, dataStore: ds, maxIdleSeconds: cfg.MaxIdleSeconds,
waitgroup: new(sync.WaitGroup)}
return &Server{
domain: cfg.Domain,
dataStore: ds,
maxIdleSeconds: cfg.MaxIdleSeconds,
globalShutdown: shutdownChan,
localShutdown: make(chan bool),
waitgroup: new(sync.WaitGroup),
}
}
// Start the server and listen for connections
@@ -52,6 +59,23 @@ func (s *Server) Start() {
panic(err)
}
// Listener go routine
go s.serve()
// Wait for shutdown
select {
case _ = <-s.globalShutdown:
}
log.Tracef("POP3 shutdown requested, connections will be drained")
// Closing the listener will cause the serve() go routine to exit
if err := s.listener.Close(); err != nil {
log.Errorf("Error closing POP3 listener: %v", err)
}
}
// serve is the listen/accept loop
func (s *Server) serve() {
// Handle incoming connections
var tempDelay time.Duration
for sid := 1; ; sid++ {
@@ -70,13 +94,16 @@ func (s *Server) Start() {
time.Sleep(tempDelay)
continue
} else {
if s.shutdown {
log.Tracef("POP3 listener shutting down on request")
// Permanent error
select {
case _ = <-s.globalShutdown:
close(s.localShutdown)
return
default:
// TODO Implement a max error counter before shutdown?
// or maybe attempt to restart smtpd
panic(err)
}
// TODO Implement a max error counter before shutdown?
// or maybe attempt to restart POP3
panic(err)
}
} else {
tempDelay = 0
@@ -86,17 +113,13 @@ func (s *Server) Start() {
}
}
// Stop requests the POP3 server closes it's listener
func (s *Server) Stop() {
log.Tracef("POP3 shutdown requested, connections will be drained")
s.shutdown = true
if err := s.listener.Close(); err != nil {
log.Errorf("Error closing POP3 listener: %v", err)
}
}
// Drain causes the caller to block until all active POP3 sessions have finished
func (s *Server) Drain() {
// Wait for listener to exit
select {
case _ = <-s.localShutdown:
}
// Wait for sessions to close
s.waitgroup.Wait()
log.Tracef("POP3 connections drained")
log.Tracef("POP3 connections have drained")
}