mirror of
https://github.com/caddyserver/caddy.git
synced 2024-12-27 14:13:48 +03:00
Close listeners which are no longer used
This commit is contained in:
parent
f976aa7443
commit
59a5d0db28
2 changed files with 40 additions and 12 deletions
17
caddy.go
17
caddy.go
|
@ -6,6 +6,7 @@ import (
|
||||||
"log"
|
"log"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -24,6 +25,7 @@ func Start(cfg Config) error {
|
||||||
cfg.runners[modName] = val.(Runner)
|
cfg.runners[modName] = val.(Runner)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// start the new runners
|
||||||
for name, r := range cfg.runners {
|
for name, r := range cfg.runners {
|
||||||
err := r.Run()
|
err := r.Run()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -32,6 +34,7 @@ func Start(cfg Config) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// shut down down the old ones
|
||||||
currentCfgMu.Lock()
|
currentCfgMu.Lock()
|
||||||
if currentCfg != nil {
|
if currentCfg != nil {
|
||||||
for _, r := range currentCfg.runners {
|
for _, r := range currentCfg.runners {
|
||||||
|
@ -44,6 +47,20 @@ func Start(cfg Config) error {
|
||||||
currentCfg = &cfg
|
currentCfg = &cfg
|
||||||
currentCfgMu.Unlock()
|
currentCfgMu.Unlock()
|
||||||
|
|
||||||
|
// shut down listeners that are no longer being used
|
||||||
|
listenersMu.Lock()
|
||||||
|
for key, info := range listeners {
|
||||||
|
if atomic.LoadInt32(&info.usage) == 0 {
|
||||||
|
err := info.ln.Close()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("[ERROR] closing listener %s: %v", info.ln.Addr(), err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
delete(listeners, key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
listenersMu.Unlock()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
35
listeners.go
35
listeners.go
|
@ -15,9 +15,10 @@ func Listen(network, addr string) (net.Listener, error) {
|
||||||
listenersMu.Lock()
|
listenersMu.Lock()
|
||||||
defer listenersMu.Unlock()
|
defer listenersMu.Unlock()
|
||||||
|
|
||||||
// if listener already exists, return it
|
// if listener already exists, increment usage counter, then return listener
|
||||||
if ln, ok := listeners[lnKey]; ok {
|
if lnInfo, ok := listeners[lnKey]; ok {
|
||||||
return &fakeCloseListener{Listener: ln}, nil
|
atomic.AddInt32(&lnInfo.usage, 1)
|
||||||
|
return &fakeCloseListener{usage: &lnInfo.usage, Listener: lnInfo.ln}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// or, create new one and save it
|
// or, create new one and save it
|
||||||
|
@ -25,9 +26,12 @@ func Listen(network, addr string) (net.Listener, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
listeners[lnKey] = ln
|
|
||||||
|
|
||||||
return &fakeCloseListener{Listener: ln}, nil
|
// make sure to start its usage counter at 1
|
||||||
|
lnInfo := &listenerUsage{usage: 1, ln: ln}
|
||||||
|
listeners[lnKey] = lnInfo
|
||||||
|
|
||||||
|
return &fakeCloseListener{usage: &lnInfo.usage, Listener: ln}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// fakeCloseListener's Close() method is a no-op. This allows
|
// fakeCloseListener's Close() method is a no-op. This allows
|
||||||
|
@ -36,7 +40,8 @@ func Listen(network, addr string) (net.Listener, error) {
|
||||||
// listener remains running. Listeners should be re-wrapped in
|
// listener remains running. Listeners should be re-wrapped in
|
||||||
// a new fakeCloseListener each time the listener is reused.
|
// a new fakeCloseListener each time the listener is reused.
|
||||||
type fakeCloseListener struct {
|
type fakeCloseListener struct {
|
||||||
closed int32
|
closed int32 // accessed atomically
|
||||||
|
usage *int32 // accessed atomically
|
||||||
net.Listener
|
net.Listener
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,16 +97,15 @@ func (fcl *fakeCloseListener) Close() error {
|
||||||
case *net.UnixListener:
|
case *net.UnixListener:
|
||||||
ln.SetDeadline(time.Now().Add(-1 * time.Minute))
|
ln.SetDeadline(time.Now().Add(-1 * time.Minute))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// since we're no longer using this listener,
|
||||||
|
// decrement the usage counter
|
||||||
|
atomic.AddInt32(fcl.usage, -1)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// CloseUnderlying actually closes the underlying listener.
|
|
||||||
func (fcl *fakeCloseListener) CloseUnderlying() error {
|
|
||||||
return fcl.Listener.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (fcl *fakeCloseListener) fakeClosedErr() error {
|
func (fcl *fakeCloseListener) fakeClosedErr() error {
|
||||||
return &net.OpError{
|
return &net.OpError{
|
||||||
Op: "accept",
|
Op: "accept",
|
||||||
|
@ -118,7 +122,14 @@ func (fcl *fakeCloseListener) fakeClosedErr() error {
|
||||||
// socket is actually left open.
|
// socket is actually left open.
|
||||||
var ErrFakeClosed = fmt.Errorf("listener 'closed' 😉")
|
var ErrFakeClosed = fmt.Errorf("listener 'closed' 😉")
|
||||||
|
|
||||||
|
// listenerUsage pairs a net.Listener with a
|
||||||
|
// count of how many servers are using it.
|
||||||
|
type listenerUsage struct {
|
||||||
|
usage int32 // accessed atomically
|
||||||
|
ln net.Listener
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
listeners = make(map[string]net.Listener)
|
listeners = make(map[string]*listenerUsage)
|
||||||
listenersMu sync.Mutex
|
listenersMu sync.Mutex
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in a new issue