Skip to content

Commit

Permalink
Merge pull request grpc#914 from flisky/master
Browse files Browse the repository at this point in the history
fix server exit due to a temporary network error
  • Loading branch information
iamqizhao authored Oct 14, 2016
2 parents 9e295f9 + e966e94 commit b057848
Showing 1 changed file with 34 additions and 5 deletions.
39 changes: 34 additions & 5 deletions server.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,10 +89,12 @@ type service struct {
type Server struct {
opts options

mu sync.Mutex // guards following
lis map[net.Listener]bool
conns map[io.Closer]bool
drain bool
mu sync.Mutex // guards following
lis map[net.Listener]bool
conns map[io.Closer]bool
drain bool
ctx context.Context
cancel context.CancelFunc
// A CondVar to let GracefulStop() blocks until all the pending RPCs are finished
// and all the transport goes away.
cv *sync.Cond
Expand Down Expand Up @@ -203,6 +205,7 @@ func NewServer(opt ...ServerOption) *Server {
m: make(map[string]*service),
}
s.cv = sync.NewCond(&s.mu)
s.ctx, s.cancel = context.WithCancel(context.Background())
if EnableTracing {
_, file, line, _ := runtime.Caller(1)
s.events = trace.NewEventLog("grpc.Server", fmt.Sprintf("%s:%d", file, line))
Expand Down Expand Up @@ -324,7 +327,7 @@ func (s *Server) useTransportAuthenticator(rawConn net.Conn) (net.Conn, credenti
// Serve accepts incoming connections on the listener lis, creating a new
// ServerTransport and service goroutine for each. The service goroutines
// read gRPC requests and then call the registered handlers to reply to them.
// Serve returns when lis.Accept fails. lis will be closed when
// Serve returns when lis.Accept fails with fatal errors. lis will be closed when
// this method returns.
func (s *Server) Serve(lis net.Listener) error {
s.mu.Lock()
Expand All @@ -344,14 +347,38 @@ func (s *Server) Serve(lis net.Listener) error {
}
s.mu.Unlock()
}()

var tempDelay time.Duration // how long to sleep on accept failure

for {
rawConn, err := lis.Accept()
if err != nil {
if ne, ok := err.(interface {
Temporary() bool
}); ok && ne.Temporary() {
if tempDelay == 0 {
tempDelay = 5 * time.Millisecond
} else {
tempDelay *= 2
}
if max := 1 * time.Second; tempDelay > max {
tempDelay = max
}
s.mu.Lock()
s.printf("Accept error: %v; retrying in %v", err, tempDelay)
s.mu.Unlock()
select {
case <-time.After(tempDelay):
case <-s.ctx.Done():
}
continue
}
s.mu.Lock()
s.printf("done serving; Accept = %v", err)
s.mu.Unlock()
return err
}
tempDelay = 0
// Start a new goroutine to deal with rawConn
// so we don't stall this Accept loop goroutine.
go s.handleRawConn(rawConn)
Expand Down Expand Up @@ -812,6 +839,7 @@ func (s *Server) Stop() {
}

s.mu.Lock()
s.cancel()
if s.events != nil {
s.events.Finish()
s.events = nil
Expand All @@ -832,6 +860,7 @@ func (s *Server) GracefulStop() {
lis.Close()
}
s.lis = nil
s.cancel()
for c := range s.conns {
c.(transport.ServerTransport).Drain()
}
Expand Down

0 comments on commit b057848

Please sign in to comment.