I am using gRPC versions:
- gRPC-protoc:26.1
- gRPC-lib:1.63.0
How can my C++ server code detect when the client has sent a message that is larger than the server's maximum size (currently using the 4 MB default).
I know how to restart my server with a larger size to get this to work. However, I want to be able to provide meaningful log information when this happens.
The current client / server environment is one where any time there is a problem "
it's the servers fault", and "
it's a hassle to reproduce the problem with debug flags enabled."
This is an example of the service my server is implementing.
```
rpc upload (stream StreamElement) returns (google.protobuf.Empty ) {}
```
And the basic skeleton of how the server works
```
grpc::Status
MyStream::upload(
grpc::ServerContext* context,
grpc::ServerReader<gRPCDicosStreamElement>* reader,
::google::protobuf::Empty* response)
{
StreamElement element;
while(reader->Read(&element))
{
... do stuff to receive the element
}
// Detect abnormal stream termination
if (context->IsCancelled())
{
... do canceled stuff, logging, etc....
return grpc::Status(grpc::StatusCode::CANCELLED, "Client cancelled");
}
return grpc::Status::OK;
}
```
I'm looking at DETECTING when a gRPC session is stopped/canceled/killed/errored
because of a message size issue. I need to detect that this problem happened so
my software can clearly instruct the user to restart the server with a larger
size.
The problem was originally observed as the following
- Client sends a streaming message to me, the server.
- Client sends a message that is larger than the 4 MB default.
- The client is ignoring the return status, and claims the server is broken.
- After a long debugging session I learned about the client / server message size conflict.
On the server
- I found that `read()` will return false because the stream has ended
- and surprisingly `context->IsCancelled()` will also return false.
So my server code thinks all is good, tries to process the accumulated stream of data and fails.
It appears the gRPC layer is detecting the problem, shutting things down and not informing me, the server application.
I tried using Message Interceptors to look into this further.
Message Intercept Test #1 - PRE_SEND_STATUSFirst I used the hook for
PRE_SEND_STATUS to view the status, but I found this was the status set/returned by my `
upload()` logic.
Message Intercept Test #2 - EVERYTHING
This is where things get interesting.
I thought I would go big and so I created an interceptor that would
print the current callback hook every time it's invoked.
If I use my library's logging method I see:
- POST_RECV_INITIAL_METADATA
- followed by a ton of POST_RECV_MESSAGE
- And then logs from my code that triggers when the upload() logic has completed. Part of which is an error about bad data received.
However,
if I use std::cerr and std::endl instead of my library's logging I see:
- POST_RECV_INITIAL_METADATA
- followed by a ton of POST_RECV_MESSAGE
- Now, is_canceled() returns true and I get the expected desired failure
Does anyone know how to do this correctly? I find it hard to believe that the library layer doesn't propagate a failure condition like this up to the application. I feel like I'm missing an API or method or pattern that would help me with this.
Thank you,
John