Skip to content

Commit

Permalink
Merge pull request grpc#903 from improbable-io/blocking-graceful-shut…
Browse files Browse the repository at this point in the history
…down-fix

Make concurrent Server.GracefulStop calls all behave equivalently.
  • Loading branch information
iamqizhao authored Oct 17, 2016
2 parents 33731fd + bac9e1d commit b7f1379
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 6 deletions.
14 changes: 8 additions & 6 deletions server.go
Original file line number Diff line number Diff line change
Expand Up @@ -527,7 +527,7 @@ func (s *Server) removeConn(c io.Closer) {
defer s.mu.Unlock()
if s.conns != nil {
delete(s.conns, c)
s.cv.Signal()
s.cv.Broadcast()
}
}

Expand Down Expand Up @@ -828,7 +828,7 @@ func (s *Server) Stop() {
st := s.conns
s.conns = nil
// interrupt GracefulStop if Stop and GracefulStop are called concurrently.
s.cv.Signal()
s.cv.Broadcast()
s.mu.Unlock()

for lis := range listeners {
Expand All @@ -852,17 +852,19 @@ func (s *Server) Stop() {
func (s *Server) GracefulStop() {
s.mu.Lock()
defer s.mu.Unlock()
if s.drain == true || s.conns == nil {
if s.conns == nil {
return
}
s.drain = true
for lis := range s.lis {
lis.Close()
}
s.lis = nil
s.cancel()
for c := range s.conns {
c.(transport.ServerTransport).Drain()
if !s.drain {
for c := range s.conns {
c.(transport.ServerTransport).Drain()
}
s.drain = true
}
for len(s.conns) != 0 {
s.cv.Wait()
Expand Down
87 changes: 87 additions & 0 deletions test/end2end_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -765,6 +765,93 @@ func testServerGoAwayPendingRPC(t *testing.T, e env) {
awaitNewConnLogOutput()
}

func TestServerMultipleGoAwayPendingRPC(t *testing.T) {
defer leakCheck(t)()
for _, e := range listTestEnv() {
if e.name == "handler-tls" {
continue
}
testServerMultipleGoAwayPendingRPC(t, e)
}
}

func testServerMultipleGoAwayPendingRPC(t *testing.T, e env) {
te := newTest(t, e)
te.userAgent = testAppUA
te.declareLogNoise(
"transport: http2Client.notifyError got notified that the client transport was broken EOF",
"grpc: addrConn.transportMonitor exits due to: grpc: the connection is closing",
"grpc: addrConn.resetTransport failed to create client transport: connection error",
)
te.startServer(&testServer{security: e.security})
defer te.tearDown()

cc := te.clientConn()
tc := testpb.NewTestServiceClient(cc)
ctx, cancel := context.WithCancel(context.Background())
stream, err := tc.FullDuplexCall(ctx, grpc.FailFast(false))
if err != nil {
t.Fatalf("%v.FullDuplexCall(_) = _, %v, want <nil>", tc, err)
}
// Finish an RPC to make sure the connection is good.
if _, err := tc.EmptyCall(context.Background(), &testpb.Empty{}, grpc.FailFast(false)); err != nil {
t.Fatalf("%v.EmptyCall(_, _, _) = _, %v, want _, <nil>", tc, err)
}
ch1 := make(chan struct{})
go func() {
te.srv.GracefulStop()
close(ch1)
}()
ch2 := make(chan struct{})
go func() {
te.srv.GracefulStop()
close(ch2)
}()
// Loop until the server side GoAway signal is propagated to the client.
for {
ctx, _ := context.WithTimeout(context.Background(), 10*time.Millisecond)
if _, err := tc.EmptyCall(ctx, &testpb.Empty{}, grpc.FailFast(false)); err == nil {
continue
}
break
}
select {
case <-ch1:
t.Fatal("GracefulStop() terminated early")
case <-ch2:
t.Fatal("GracefulStop() terminated early")
default:
}
respParam := []*testpb.ResponseParameters{
{
Size: proto.Int32(1),
},
}
payload, err := newPayload(testpb.PayloadType_COMPRESSABLE, int32(100))
if err != nil {
t.Fatal(err)
}
req := &testpb.StreamingOutputCallRequest{
ResponseType: testpb.PayloadType_COMPRESSABLE.Enum(),
ResponseParameters: respParam,
Payload: payload,
}
// The existing RPC should be still good to proceed.
if err := stream.Send(req); err != nil {
t.Fatalf("%v.Send(%v) = %v, want <nil>", stream, req, err)
}
if _, err := stream.Recv(); err != nil {
t.Fatalf("%v.Recv() = _, %v, want _, <nil>", stream, err)
}
if err := stream.CloseSend(); err != nil {
t.Fatalf("%v.CloseSend() = %v, want <nil>", stream, err)
}
<-ch1
<-ch2
cancel()
awaitNewConnLogOutput()
}

func TestConcurrentClientConnCloseAndServerGoAway(t *testing.T) {
defer leakCheck(t)()
for _, e := range listTestEnv() {
Expand Down

0 comments on commit b7f1379

Please sign in to comment.