Skip to content

Commit ba6f8b9

Browse files
Fix grpc middleware interceptor not PostCall-ing when a streaming RPC with non-streaming server finishes successfully. (#725)
* Fix grpc middleware interceptor not PostCall-ing when a streaming RPC with non-streaming server finishes. * add test, bump grpc * Rename client stream method * Lint fixes * Even more linting --------- Co-authored-by: monocleus <[email protected]>
1 parent bbb4d69 commit ba6f8b9

File tree

8 files changed

+426
-357
lines changed

8 files changed

+426
-357
lines changed

go.mod

+9-9
Original file line numberDiff line numberDiff line change
@@ -6,26 +6,26 @@ require (
66
buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.31.0-20230802163732-1c33ebd9ecfa.1
77
github.com/bufbuild/protovalidate-go v0.2.1
88
github.com/stretchr/testify v1.8.4
9-
golang.org/x/net v0.21.0
10-
golang.org/x/oauth2 v0.16.0
11-
google.golang.org/grpc v1.61.1
12-
google.golang.org/protobuf v1.32.0
9+
golang.org/x/net v0.28.0
10+
golang.org/x/oauth2 v0.22.0
11+
google.golang.org/grpc v1.67.1
12+
google.golang.org/protobuf v1.34.2
1313
)
1414

1515
require (
1616
cloud.google.com/go/compute v1.23.4 // indirect
17-
cloud.google.com/go/compute/metadata v0.2.3 // indirect
17+
cloud.google.com/go/compute/metadata v0.5.0 // indirect
1818
github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230512164433-5d1fd1a340c9 // indirect
1919
github.com/davecgh/go-spew v1.1.1 // indirect
2020
github.com/golang/protobuf v1.5.3 // indirect
2121
github.com/google/cel-go v0.17.1 // indirect
2222
github.com/pmezard/go-difflib v1.0.0 // indirect
2323
github.com/stoewer/go-strcase v1.3.0 // indirect
2424
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 // indirect
25-
golang.org/x/sys v0.17.0 // indirect
26-
golang.org/x/text v0.14.0 // indirect
25+
golang.org/x/sys v0.24.0 // indirect
26+
golang.org/x/text v0.17.0 // indirect
2727
google.golang.org/appengine v1.6.8 // indirect
28-
google.golang.org/genproto/googleapis/api v0.0.0-20240125205218-1f4bbc51befe // indirect
29-
google.golang.org/genproto/googleapis/rpc v0.0.0-20240213162025-012b6fc9bca9 // indirect
28+
google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142 // indirect
29+
google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 // indirect
3030
gopkg.in/yaml.v3 v3.0.1 // indirect
3131
)

go.sum

+19
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ cloud.google.com/go/compute v1.23.4 h1:EBT9Nw4q3zyE7G45Wvv3MzolIrCJEuHys5muLY0wv
44
cloud.google.com/go/compute v1.23.4/go.mod h1:/EJMj55asU6kAFnuZET8zqgwgJ9FvXWXOkkfQZa4ioI=
55
cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY=
66
cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA=
7+
cloud.google.com/go/compute/metadata v0.5.0 h1:Zr0eK8JbFv6+Wi4ilXAR8FJ3wyNdpxHKJNPos6LTZOY=
8+
cloud.google.com/go/compute/metadata v0.5.0/go.mod h1:aHnloV2TPI38yx4s9+wAZhHykWvVCfu7hQbF+9CWoiY=
79
github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230512164433-5d1fd1a340c9 h1:goHVqTbFX3AIo0tzGr14pgfAW2ZfPChKO21Z9MGf/gk=
810
github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230512164433-5d1fd1a340c9/go.mod h1:pSwJ0fSY5KhvocuWSx4fz3BA8OrA1bQn+K1Eli3BRwM=
911
github.com/bufbuild/protovalidate-go v0.2.1 h1:pJr07sYhliyfj/STAM7hU4J3FKpVeLVKvOBmOTN8j+s=
@@ -13,6 +15,7 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
1315
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
1416
github.com/envoyproxy/protoc-gen-validate v1.0.2 h1:QkIBuU5k+x7/QXPvPPnWXWlCdaBFApVqftFV6k087DA=
1517
github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE=
18+
github.com/envoyproxy/protoc-gen-validate v1.1.0 h1:tntQDh69XqOCOZsDz0lVJQez/2L6Uu2PdjCQwWCJ3bM=
1619
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
1720
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
1821
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
@@ -49,8 +52,12 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v
4952
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
5053
golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
5154
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
55+
golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
56+
golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
5257
golang.org/x/oauth2 v0.16.0 h1:aDkGMBSYxElaoP81NpoUoz2oo2R2wHdZpGToUxfyQrQ=
5358
golang.org/x/oauth2 v0.16.0/go.mod h1:hqZ+0LWXsiVoZpeld6jVt06P3adbS2Uu911W1SsJv2o=
59+
golang.org/x/oauth2 v0.22.0 h1:BzDx2FehcG7jJwgWLELCdmLuxk2i+x9UDpSiss2u0ZA=
60+
golang.org/x/oauth2 v0.22.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
5461
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
5562
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
5663
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -60,6 +67,8 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc
6067
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
6168
golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
6269
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
70+
golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg=
71+
golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
6372
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
6473
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
6574
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -68,6 +77,8 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
6877
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
6978
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
7079
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
80+
golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc=
81+
golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
7182
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
7283
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
7384
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
@@ -77,15 +88,23 @@ google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAs
7788
google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=
7889
google.golang.org/genproto/googleapis/api v0.0.0-20240125205218-1f4bbc51befe h1:0poefMBYvYbs7g5UkjS6HcxBPaTRAmznle9jnxYoAI8=
7990
google.golang.org/genproto/googleapis/api v0.0.0-20240125205218-1f4bbc51befe/go.mod h1:4jWUdICTdgc3Ibxmr8nAJiiLHwQBY0UI0XZcEMaFKaA=
91+
google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142 h1:wKguEg1hsxI2/L3hUYrpo1RVi48K+uTyzKqprwLXsb8=
92+
google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142/go.mod h1:d6be+8HhtEtucleCbxpPW9PA9XwISACu8nvpPqF0BVo=
8093
google.golang.org/genproto/googleapis/rpc v0.0.0-20240213162025-012b6fc9bca9 h1:hZB7eLIaYlW9qXRfCq/qDaPdbeY3757uARz5Vvfv+cY=
8194
google.golang.org/genproto/googleapis/rpc v0.0.0-20240213162025-012b6fc9bca9/go.mod h1:YUWgXUFRPfoYK1IHMuxH5K6nPEXSCzIMljnQ59lLRCk=
95+
google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 h1:e7S5W7MGGLaSu8j3YjdezkZ+m1/Nm0uRVRMEMGk26Xs=
96+
google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
8297
google.golang.org/grpc v1.61.1 h1:kLAiWrZs7YeDM6MumDe7m3y4aM6wacLzM1Y/wiLP9XY=
8398
google.golang.org/grpc v1.61.1/go.mod h1:VUbo7IFqmF1QtCAstipjG0GIoq49KvMe9+h1jFLBNJs=
99+
google.golang.org/grpc v1.67.1 h1:zWnc1Vrcno+lHZCOofnIMvycFcc0QRGIzm9dhnDX68E=
100+
google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA=
84101
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
85102
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
86103
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
87104
google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I=
88105
google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
106+
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
107+
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
89108
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
90109
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
91110
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

interceptors/client.go

+15-10
Original file line numberDiff line numberDiff line change
@@ -38,16 +38,17 @@ func StreamClientInterceptor(reportable ClientReportable) grpc.StreamClientInter
3838
reporter.PostCall(err, time.Since(r.startTime))
3939
return nil, err
4040
}
41-
return &monitoredClientStream{ClientStream: clientStream, startTime: r.startTime, reporter: reporter}, nil
41+
return &monitoredClientStream{ClientStream: clientStream, startTime: r.startTime, hasServerStream: desc.ServerStreams, reporter: reporter}, nil
4242
}
4343
}
4444

4545
// monitoredClientStream wraps grpc.ClientStream allowing each Sent/Recv of message to report.
4646
type monitoredClientStream struct {
4747
grpc.ClientStream
4848

49-
startTime time.Time
50-
reporter Reporter
49+
startTime time.Time
50+
hasServerStream bool
51+
reporter Reporter
5152
}
5253

5354
func (s *monitoredClientStream) SendMsg(m any) error {
@@ -62,13 +63,17 @@ func (s *monitoredClientStream) RecvMsg(m any) error {
6263
err := s.ClientStream.RecvMsg(m)
6364
s.reporter.PostMsgReceive(m, err, time.Since(start))
6465

65-
if err == nil {
66-
return nil
67-
}
68-
var postErr error
69-
if err != io.EOF {
70-
postErr = err
66+
if s.hasServerStream {
67+
if err == nil {
68+
return nil
69+
}
70+
var postErr error
71+
if err != io.EOF {
72+
postErr = err
73+
}
74+
s.reporter.PostCall(postErr, time.Since(s.startTime))
75+
} else {
76+
s.reporter.PostCall(err, time.Since(s.startTime))
7177
}
72-
s.reporter.PostCall(postErr, time.Since(s.startTime))
7378
return err
7479
}

interceptors/client_test.go

+23
Original file line numberDiff line numberDiff line change
@@ -337,3 +337,26 @@ func (s *ClientInterceptorTestSuite) TestBiStreamingReporting() {
337337
postMsgSends: make([]error, 100),
338338
}})
339339
}
340+
341+
func (s *ClientInterceptorTestSuite) TestClientStream() {
342+
ss, err := s.testClient.PingClientStream(s.ctx)
343+
require.NoError(s.T(), err)
344+
345+
defer func() {
346+
_, _ = ss.CloseAndRecv()
347+
}()
348+
349+
for i := 0; i < 100; i++ {
350+
require.NoError(s.T(), ss.Send(&testpb.PingClientStreamRequest{}), "sending shouldn't fail")
351+
}
352+
353+
_, err = ss.CloseAndRecv()
354+
require.NoError(s.T(), err)
355+
356+
s.mock.Equal(s.T(), []*mockReport{{
357+
CallMeta: CallMeta{Typ: ClientStream, Service: testpb.TestServiceFullName, Method: "PingClientStream"},
358+
postCalls: []error{nil},
359+
postMsgReceives: []error{nil},
360+
postMsgSends: make([]error, 100),
361+
}})
362+
}

testing/testpb/pingservice.go

+16-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ const (
2020
ListResponseCount = 100
2121
)
2222

23-
var TestServiceFullName = _TestService_serviceDesc.ServiceName
23+
var TestServiceFullName = TestService_ServiceDesc.ServiceName
2424

2525
// Interface implementation assert.
2626
var _ TestServiceServer = &TestPingService{}
@@ -80,3 +80,18 @@ func (s *TestPingService) PingStream(stream TestService_PingStreamServer) error
8080
}
8181
return nil
8282
}
83+
84+
func (s *TestPingService) PingClientStream(stream TestService_PingClientStreamServer) error {
85+
count := 0
86+
for {
87+
_, err := stream.Recv()
88+
if err == io.EOF {
89+
break
90+
}
91+
if err != nil {
92+
return err
93+
}
94+
count += 1
95+
}
96+
return stream.SendAndClose(&PingClientStreamResponse{Counter: int32(count)})
97+
}

0 commit comments

Comments
 (0)