Skip to content

grpc: Fix cardinality violations in client streaming and unary RPCs. #8330

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
May 28, 2025

Conversation

Pranjali-2501
Copy link
Contributor

@Pranjali-2501 Pranjali-2501 commented May 15, 2025

Client should ensure an INTERNAL error is returned for non-server streaming RPCs if the server attempts to send more than one response.
Currently it is returning UNKNOWN, which should not be the case for cardinality violations.

Filed in #7286
RELEASE NOTES:

  • grpc: unary and client-streaming RPCs fail with internal status when server sends multiple response messages.

Copy link

codecov bot commented May 15, 2025

Codecov Report

Attention: Patch coverage is 50.00000% with 1 line in your changes missing coverage. Please review.

Project coverage is 82.20%. Comparing base (6821606) to head (0441021).
Report is 41 commits behind head on master.

Files with missing lines Patch % Lines
stream.go 50.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #8330      +/-   ##
==========================================
- Coverage   82.25%   82.20%   -0.05%     
==========================================
  Files         417      419       +2     
  Lines       41356    42039     +683     
==========================================
+ Hits        34017    34560     +543     
- Misses       5923     6008      +85     
- Partials     1416     1471      +55     
Files with missing lines Coverage Δ
stream.go 81.91% <50.00%> (+0.35%) ⬆️

... and 57 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@Pranjali-2501 Pranjali-2501 added this to the 1.73 Release milestone May 15, 2025
@Pranjali-2501 Pranjali-2501 self-assigned this May 15, 2025
@dfawley
Copy link
Member

dfawley commented May 16, 2025

@Pranjali-2501 please use the Assignees field to indicate who needs to act on the PR next. I assume you have meant to assign this to @arjan-bal and me?

@dfawley dfawley assigned dfawley and arjan-bal and unassigned Pranjali-2501 May 16, 2025
Copy link
Member

@dfawley dfawley left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great, just a couple really small things. Thanks!

@@ -3739,6 +3739,39 @@ func (s) TestClientStreaming_ReturnErrorAfterSendAndClose(t *testing.T) {
}
}

// Tests that a client receives a cardinality violation error for client-streaming
// RPCs if the server call SendAndClose after calling SendAndClose.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// RPCs if the server call SendAndClose after calling SendAndClose.
// RPCs if the server calls SendAndClose multiple times.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

t.Fatalf("stream.Send(_) = %v, want <nil>", err)
}
if _, err := stream.CloseAndRecv(); status.Code(err) != codes.Internal {
t.Fatalf("stream.CloseAndRecv() = %v, want error %s", err, codes.Internal)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
t.Fatalf("stream.CloseAndRecv() = %v, want error %s", err, codes.Internal)
t.Fatalf("stream.CloseAndRecv() = %v, want error with status code %s", err, codes.Internal)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@dfawley dfawley assigned Pranjali-2501 and unassigned dfawley May 20, 2025
stream.go Outdated
@@ -1167,7 +1167,7 @@ func (a *csAttempt) recvMsg(m any, payInfo *payloadInfo) (err error) {
} else if err != nil {
return toRPCErr(err)
}
return toRPCErr(errors.New("grpc: client streaming protocol violation: get <nil>, want <EOF>"))
return status.Errorf(codes.Internal, "client streaming cardinality violation: get <nil>, want <EOF>")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a similar method on addrConnStream that also needs to be updated.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

Copy link
Contributor

@arjan-bal arjan-bal left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM with minor comments.

func (s) TestClientStreaming_ServerHandlerSendAndCloseAfterSendAndClose(t *testing.T) {
ss := stubserver.StubServer{
StreamingInputCallF: func(stream testgrpc.TestService_StreamingInputCallServer) error {
if err := stream.SendAndClose(&testpb.StreamingInputCallResponse{}); err != nil {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my opinion, we should call Send instead of SendAndClose. SendAndClose doesn't actually close the stream, but it can confuse readers why the server didn't get an error when trying to write to a closed stream.

Copy link
Contributor Author

@Pranjali-2501 Pranjali-2501 May 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SendAndClose() have been used for all client-streaming test cases. To maintain the consistency, I have used SendAndClose() in new tests.

If all occurrences of SendAndClose() needs to be replaced by Send(), I'll do that in a separate PR.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Existing refferences use SendAndClose probably because the intention is to close the stream (even though closing doesn't happen until the handler returns). This is not done for consistency. In this test, we want to send multiple message and not close, so I would suggest just changing this test to use Close(). We don't need to change the remaining tests. Both Send and SendAndClose are part of the stable API.

Copy link
Contributor Author

@Pranjali-2501 Pranjali-2501 May 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Send() method is not defined in StreamingInputCall. So I have used SendMsg() instead of Send().

Let me know if you want me to use Send() only. I will then change the complete test.

stream.go Outdated
@@ -1167,7 +1167,7 @@ func (a *csAttempt) recvMsg(m any, payInfo *payloadInfo) (err error) {
} else if err != nil {
return toRPCErr(err)
}
return toRPCErr(errors.New("grpc: client streaming protocol violation: get <nil>, want <EOF>"))
return status.Errorf(codes.Internal, "client streaming cardinality violation: get <nil>, want <EOF>")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can improve this error message to say something like:
cardinality violation: expected EOF from non-streaming server, but received another message. I believe this can also happen in unary RPCs.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The message still says "" instead of "another message". When a user sees "got nil", they would need to lookup the implementation to understand what it means. If we say "another message", the failure condition is clearer.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Made the changes.

Copy link
Contributor

@arjan-bal arjan-bal left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving.

@Pranjali-2501 Pranjali-2501 changed the title Cardinality violations in Client streaming and Unary RPC. grpc: Fix cardinality violations in client streaming and unary RPCs. May 28, 2025
@arjan-bal arjan-bal merged commit ec4810c into grpc:master May 28, 2025
15 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants