Let net/http gracefully close
http.Server.Shutdown gracefully closes listeners/clients, we do not have to do it ourselves. Making util/signals accept func() instead of io.Closer allowed for the removal of network/closer.go and util/signals/closers.go.
Cette révision appartient à :
Parent
0159579611
révision
0bdd915f9a
4 fichiers modifiés avec 44 ajouts et 62 suppressions
42
main.go
42
main.go
|
@ -4,6 +4,7 @@ import (
|
|||
"bufio"
|
||||
"flag"
|
||||
|
||||
"context"
|
||||
"net/http"
|
||||
"os"
|
||||
"time"
|
||||
|
@ -37,19 +38,24 @@ func RunServer(conf *config.Config) {
|
|||
}
|
||||
l, err := network.CreateHTTPListener(conf)
|
||||
log.CheckError(err)
|
||||
if err == nil {
|
||||
// add http server to be closed gracefully
|
||||
signals.RegisterCloser(&network.GracefulHttpCloser{
|
||||
Server: srv,
|
||||
Listener: l,
|
||||
})
|
||||
log.Infof("listening on %s", l.Addr())
|
||||
err := srv.Serve(l)
|
||||
if err != nil && err != network.ErrListenerStopped {
|
||||
log.CheckError(err)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
log.Infof("listening on %s", l.Addr())
|
||||
// http.Server.Shutdown closes associated listeners/clients.
|
||||
// context.Background causes srv to indefinitely try to
|
||||
// gracefully shutdown. add a timeout if this becomes a problem.
|
||||
signals.OnInterrupt(func() {
|
||||
srv.Shutdown(context.Background())
|
||||
})
|
||||
err = srv.Serve(l)
|
||||
if err == nil {
|
||||
log.Panic("http.Server.Serve never returns nil")
|
||||
}
|
||||
if err == http.ErrServerClosed {
|
||||
return
|
||||
}
|
||||
log.CheckError(err)
|
||||
}
|
||||
|
||||
// RunScraper runs tracker scraper mainloop
|
||||
|
@ -73,10 +79,10 @@ func RunScraper(conf *config.Config) {
|
|||
workers = 1
|
||||
}
|
||||
|
||||
// register udp socket with signals
|
||||
signals.RegisterCloser(pc)
|
||||
// register scraper with signals
|
||||
signals.RegisterCloser(scraper)
|
||||
signals.OnInterrupt(func() {
|
||||
pc.Close()
|
||||
scraper.Close()
|
||||
})
|
||||
// run udp scraper worker
|
||||
for workers > 0 {
|
||||
log.Infof("starting up worker %d", workers)
|
||||
|
@ -96,7 +102,9 @@ func RunMetainfoFetcher(conf *config.Config) {
|
|||
return
|
||||
}
|
||||
|
||||
signals.RegisterCloser(fetcher)
|
||||
signals.OnInterrupt(func() {
|
||||
fetcher.Close()
|
||||
})
|
||||
fetcher.RunAsync()
|
||||
fetcher.Wait()
|
||||
}
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
package network
|
||||
|
||||
import (
|
||||
"net"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// GracefulHttpCloser : implements io.Closer that gracefully closes an http server
|
||||
type GracefulHttpCloser struct {
|
||||
Server *http.Server
|
||||
Listener net.Listener
|
||||
}
|
||||
|
||||
// Close method
|
||||
func (c *GracefulHttpCloser) Close() error {
|
||||
c.Listener.Close()
|
||||
return c.Server.Shutdown(nil)
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
package signals
|
||||
|
||||
import (
|
||||
"io"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var (
|
||||
closeAccess sync.Mutex
|
||||
closers []io.Closer
|
||||
)
|
||||
|
||||
// RegisterCloser adds an io.Closer to close on interrupt
|
||||
func RegisterCloser(c io.Closer) {
|
||||
closeAccess.Lock()
|
||||
closers = append(closers, c)
|
||||
closeAccess.Unlock()
|
||||
}
|
||||
|
||||
func closeClosers() {
|
||||
closeAccess.Lock()
|
||||
for _, c := range closers {
|
||||
c.Close()
|
||||
}
|
||||
closeAccess.Unlock()
|
||||
}
|
|
@ -3,8 +3,22 @@ package signals
|
|||
import (
|
||||
"github.com/NyaaPantsu/nyaa/router"
|
||||
"github.com/NyaaPantsu/nyaa/util/log"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// registered interrupt callbacks.
|
||||
// currently only used to gracefully close the server.
|
||||
var intEvents struct {
|
||||
lock sync.Mutex
|
||||
funcs []func()
|
||||
}
|
||||
|
||||
func OnInterrupt(fn func()) {
|
||||
intEvents.lock.Lock()
|
||||
intEvents.funcs = append(intEvents.funcs, fn)
|
||||
intEvents.lock.Unlock()
|
||||
}
|
||||
|
||||
func handleReload() {
|
||||
log.Info("Got SIGHUP")
|
||||
router.ReloadTemplates()
|
||||
|
@ -13,5 +27,9 @@ func handleReload() {
|
|||
|
||||
// handle interrupt signal, platform independent
|
||||
func interrupted() {
|
||||
closeClosers()
|
||||
intEvents.lock.Lock()
|
||||
for _, fn := range intEvents.funcs {
|
||||
fn()
|
||||
}
|
||||
intEvents.lock.Unlock()
|
||||
}
|
||||
|
|
Référencer dans un nouveau ticket