Skip to content

Commit b70d961

Browse files
committed
temp fix
1 parent 511a231 commit b70d961

File tree

2 files changed

+78
-75
lines changed

2 files changed

+78
-75
lines changed

cmd/web.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,7 @@ func serveInstalled(c *cli.Command) error {
169169

170170
showWebStartupMessage("Prepare to run web server")
171171

172+
// FIXME: remove it if it doesn't really help
172173
// Check for shutdown signal during startup
173174
select {
174175
case <-graceful.GetManager().IsShutdown():
@@ -235,6 +236,7 @@ func serveInstalled(c *cli.Command) error {
235236

236237
gtprof.EnableBuiltinTracer(util.Iif(setting.IsProd, 2000*time.Millisecond, 100*time.Millisecond))
237238

239+
// FIXME: remove it if it doesn't really help
238240
// Check for shutdown signal before starting web server
239241
select {
240242
case <-graceful.GetManager().IsShutdown():

modules/graceful/server.go

Lines changed: 76 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@
66
package graceful
77

88
import (
9+
"container/list"
910
"crypto/tls"
1011
"net"
1112
"os"
1213
"strings"
1314
"sync"
14-
"sync/atomic"
1515
"syscall"
1616
"time"
1717

@@ -30,14 +30,15 @@ type ServeFunction = func(net.Listener) error
3030

3131
// Server represents our graceful server
3232
type Server struct {
33-
network string
34-
address string
35-
listener net.Listener
36-
wg sync.WaitGroup
37-
state state
38-
lock *sync.RWMutex
39-
connections map[*wrappedConn]struct{}
40-
connectionsLock sync.RWMutex
33+
network string
34+
address string
35+
listener net.Listener
36+
37+
lock sync.RWMutex
38+
state state
39+
connList *list.List
40+
connEmptyCond *sync.Cond
41+
4142
BeforeBegin func(network, address string)
4243
OnShutdown func()
4344
PerWriteTimeout time.Duration
@@ -52,15 +53,14 @@ func NewServer(network, address, name string) *Server {
5253
log.Info("Starting new %s server: %s:%s on PID: %d", name, network, address, os.Getpid())
5354
}
5455
srv := &Server{
55-
wg: sync.WaitGroup{},
5656
state: stateInit,
57-
lock: &sync.RWMutex{},
58-
connections: make(map[*wrappedConn]struct{}),
57+
connList: list.New(),
5958
network: network,
6059
address: address,
6160
PerWriteTimeout: setting.PerWriteTimeout,
6261
PerWritePerKbTimeout: setting.PerWritePerKbTimeout,
6362
}
63+
srv.connEmptyCond = sync.NewCond(&srv.lock)
6464

6565
srv.BeforeBegin = func(network, addr string) {
6666
log.Debug("Starting server on %s:%s (PID: %d)", network, addr, syscall.Getpid())
@@ -157,7 +157,7 @@ func (srv *Server) Serve(serve ServeFunction) error {
157157
GetManager().RegisterServer()
158158
err := serve(srv.listener)
159159
log.Debug("Waiting for connections to finish... (PID: %d)", syscall.Getpid())
160-
srv.wg.Wait()
160+
srv.waitForActiveConnections()
161161
srv.setState(stateTerminate)
162162
GetManager().ServerDone()
163163
// use of closed means that the listeners are closed - i.e. we should be shutting down - return nil
@@ -181,19 +181,57 @@ func (srv *Server) setState(st state) {
181181
srv.state = st
182182
}
183183

184+
func (srv *Server) waitForActiveConnections() {
185+
srv.lock.Lock()
186+
for srv.connList.Len() > 0 {
187+
srv.connEmptyCond.Wait()
188+
}
189+
srv.lock.Unlock()
190+
}
191+
192+
func (srv *Server) wrapConnection(c net.Conn) (net.Conn, error) {
193+
srv.lock.Lock()
194+
defer srv.lock.Unlock()
195+
196+
if srv.state != stateRunning {
197+
_ = c.Close()
198+
return nil, syscall.EINVAL // same as AcceptTCP
199+
}
200+
201+
wc := &wrappedConn{Conn: c, server: srv}
202+
wc.listElem = srv.connList.PushBack(wc)
203+
return wc, nil
204+
}
205+
206+
func (srv *Server) removeConnection(conn *wrappedConn) {
207+
srv.lock.Lock()
208+
defer srv.lock.Unlock()
209+
210+
if conn.listElem == nil {
211+
return
212+
}
213+
srv.connList.Remove(conn.listElem)
214+
if srv.connList.Len() == 0 {
215+
srv.connEmptyCond.Broadcast()
216+
}
217+
}
218+
184219
// closeAllConnections forcefully closes all active connections
185220
func (srv *Server) closeAllConnections() {
186-
srv.connectionsLock.Lock()
187-
connections := make([]*wrappedConn, 0, len(srv.connections))
188-
for conn := range srv.connections {
189-
connections = append(connections, conn)
221+
srv.lock.Lock()
222+
conns := make([]*wrappedConn, 0, srv.connList.Len())
223+
for e := srv.connList.Front(); e != nil; e = e.Next() {
224+
conn := e.Value.(*wrappedConn)
225+
conn.listElem = nil // mark as removed, will close it later to avoid deadlock of "server.lock"
226+
conns = append(conns, conn)
190227
}
191-
srv.connectionsLock.Unlock()
228+
srv.connList = list.New()
229+
srv.lock.Unlock()
192230

193-
// Close all connections outside the lock to avoid deadlock
194-
for _, conn := range connections {
195-
_ = conn.Conn.Close() // Force close the underlying connection
231+
for _, conn := range conns {
232+
_ = conn.Close() // do real close outside of lock
196233
}
234+
srv.connEmptyCond.Broadcast()
197235
}
198236

199237
type filer interface {
@@ -202,61 +240,39 @@ type filer interface {
202240

203241
type wrappedListener struct {
204242
net.Listener
205-
stopped bool
206-
server *Server
243+
server *Server
207244
}
208245

246+
var (
247+
_ net.Listener = (*wrappedListener)(nil)
248+
_ filer = (*wrappedListener)(nil)
249+
)
250+
209251
func newWrappedListener(l net.Listener, srv *Server) *wrappedListener {
210252
return &wrappedListener{
211253
Listener: l,
212254
server: srv,
213255
}
214256
}
215257

216-
func (wl *wrappedListener) Accept() (net.Conn, error) {
217-
var c net.Conn
218-
// Set keepalive on TCPListeners connections.
258+
func (wl *wrappedListener) Accept() (c net.Conn, err error) {
219259
if tcl, ok := wl.Listener.(*net.TCPListener); ok {
260+
// Set keepalive on TCPListeners connections if possible, http.tcpKeepAliveListener
220261
tc, err := tcl.AcceptTCP()
221262
if err != nil {
222263
return nil, err
223264
}
224-
_ = tc.SetKeepAlive(true) // see http.tcpKeepAliveListener
225-
_ = tc.SetKeepAlivePeriod(3 * time.Minute) // see http.tcpKeepAliveListener
265+
_ = tc.SetKeepAlive(true)
266+
_ = tc.SetKeepAlivePeriod(3 * time.Minute)
226267
c = tc
227268
} else {
228-
var err error
229269
c, err = wl.Listener.Accept()
230270
if err != nil {
231271
return nil, err
232272
}
233273
}
234274

235-
closed := int32(0)
236-
237-
wc := &wrappedConn{
238-
Conn: c,
239-
server: wl.server,
240-
closed: &closed,
241-
}
242-
243-
wl.server.wg.Add(1)
244-
245-
// Track the connection
246-
wl.server.connectionsLock.Lock()
247-
wl.server.connections[wc] = struct{}{}
248-
wl.server.connectionsLock.Unlock()
249-
250-
return wc, nil
251-
}
252-
253-
func (wl *wrappedListener) Close() error {
254-
if wl.stopped {
255-
return syscall.EINVAL
256-
}
257-
258-
wl.stopped = true
259-
return wl.Listener.Close()
275+
return wl.server.wrapConnection(c)
260276
}
261277

262278
func (wl *wrappedListener) File() (*os.File, error) {
@@ -266,8 +282,12 @@ func (wl *wrappedListener) File() (*os.File, error) {
266282

267283
type wrappedConn struct {
268284
net.Conn
285+
286+
// listElem is protected by the server's lock (used by the server to remove conn itself from the list)
287+
// nil means it has been removed
288+
listElem *list.Element
289+
269290
server *Server
270-
closed *int32
271291
deadline time.Time
272292
}
273293

@@ -286,25 +306,6 @@ func (w *wrappedConn) Write(p []byte) (n int, err error) {
286306
}
287307

288308
func (w *wrappedConn) Close() error {
289-
if atomic.CompareAndSwapInt32(w.closed, 0, 1) {
290-
defer func() {
291-
if err := recover(); err != nil {
292-
select {
293-
case <-GetManager().IsHammer():
294-
// Likely deadlocked request released at hammertime
295-
log.Warn("Panic during connection close! %v. Likely there has been a deadlocked request which has been released by forced shutdown.", err)
296-
default:
297-
log.Error("Panic during connection close! %v", err)
298-
}
299-
}
300-
}()
301-
302-
// Remove from tracked connections
303-
w.server.connectionsLock.Lock()
304-
delete(w.server.connections, w)
305-
w.server.connectionsLock.Unlock()
306-
307-
w.server.wg.Done()
308-
}
309+
w.server.removeConnection(w)
309310
return w.Conn.Close()
310311
}

0 commit comments

Comments
 (0)