-
Notifications
You must be signed in to change notification settings - Fork 4.4k
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
docs: Do nil headers from stream.Header() indicate an error? #6524
Comments
Hi, It is not safe to assume a This particular scenario seems like you want to implement a proxy. In which case, if
the blocking read is totally depended on the application's implementation of BiDi streaming. The client could be blocking Recv() if the server has never sent anything on the stream. But in the case of the server explicitly returning an error and closing the stream, you can totally rely on Recv() to return that error and relay that to upstream. Let us know if this answers your question. |
My situation is that the server will process the request message and either:
My problem is that there is no way to definitely detect this error returned before any messages without potentially blocking to wait for a message that may never arrive. This seems defective to me, as the protocol and underlying clientStream knows there is an error, it has already parsed the trailers response containing the error, but instead of returning it, it hides it until I make a call that could possibly block. IMO But I can see how a strict interpretation is that it is a method for returning headers and not trailers, so returning nil to indicate there were no headers makes a kind sense. If the documentation stated that |
Hi, I'm not sure if I understand the problem here.
Server returns an error for an invalid request sent on the stream by the client. Does that mean the client sends the first message on the stream? Wouldnt the client also call recv() on the stream after sending a request? - which should return the error from the server? In gRPC, calling I'm not convinced there is a case where the client relies on stream.Header() to detect error from server rather than relying on the error returned from recv(). |
Yes, but there is a unique underlying (HTTP2) stream that is in a definitive state. In my case, after waiting for headers, the stream has terminated with a trailers-only response including an error. You are correct the HTTP2 connection may still be alive, but the stream on that connection is in a known terminal state. I am talking the HTTP2 stream whose state corresponds to the state of the gRPC stream, not the transport connection.
The problem is timeouts. recv() only returns an error quickly if there is an error, else it can block until the server decides to send something. Here is my case: the semantics of my unary->stream call are that the unary message is either accepted for establishing a stream or rejected. The gRPC client is an HTTP server making the call as part of handling an upstream HTTP request. If the gRPC request is accepted, the gRPC server indicates this by sending the headers. So the server is explicitly indicating the request was OK. At this point, the gRPC client ought to be able report a status to the upstream HTTP client indicating the request was accepted. Except it can't, because we don't know if there was an error, we have to recv() to check that. If there was no error: the gRPC client calls You might suggest that I have a separate goroutine invoke When Experimentation leads me to believe that Documentation that states that some current behavior ( |
the problem is that it is not safe to assume a In your particular case, here are 2 suggested modification you could try implementing
|
OK. Then I think this is an implementation bug that when I wait for headers, I cannot learn whether headers were actually received or not. The server is sending a message: it is sending either headers or closing the stream. Just give me access to that information! That's all am I asking for. If the implementation does not provide a way to do that, can someone please explain how that is not a defect in the implementation? |
The server only sends headers when your method handler instructs it to (grpc.SendHeader for unary or ServerStream.SendHeader for streaming), or before it sends its first response message. If you aren't sending an explicit message, then you need to be doing one of those other two things to make sure the headers are sent.
Why would it block indefinitely? If an error is always written to the stream,
If you really want to, but I wouldn't recommend it. Yes,
We only return RPC errors when |
@dfawley I started with an example that didn't make sense to me at the time (always returning an error produces no error from Header()) I now understand the reasoning for errors being returned by Recv(), which makes senes. My problem is that I have a server (as described here) that will either: 1. return an error immediately (without sending messages or headers,) or 2. send headers and then at some (perhaps much) later time send a message. So headers are indication that the stream setup was successful. The problem is that in the non-failure case (2), recv can block indefinitely, so I can't return status upstream in a timely way. I am very frustrated by this because if you look at the http2 stream after Header() returns, the state is known: it has either already received the error and the stream is terminated, or it received some kind of headers and is waiting for more frames. As a user, I cannot access that state. I just want to know if I really received headers or not. The later means I can invoke Recv() without having to worry that it will block indefinitely. If it were documented that |
Upon closer inspection, it seems there is a bug here that was introduced with #5763. Before that change, the With the fix, if |
@dfawley amazing! Thank you! |
Hmm, actually it seems this was not correct. Even before that change, a trailers-only response would have returned Also, some of our users were depending on this behavior of If we did this, we'd need to find another way to solve your concerns.... |
I think the most reasonable way to do this would be to document that |
I have an
rpc Test(TestRequest) returns (stream TestMessage)
with an implementation that just returns an error immediately.Then the client does this:
What is flummoxing me is that most of the time, but not always,
stream.Header()
returnsnil, nil
. Occasionally, running in a debugger, it returns the error. A calls tostream.Recv()
returns the error reliably, but IDK if there is an error or not, and could end up blocking indefinitely waiting for it, which isn’t good because I have an upstream waiting to know the stream was setup successfully.What I noticed is that if there was an error, I get
nil
headers instead ofcontent-type: ...
. Can I reliably use this as a signal to invokeRecv()
and get the underlying error?Why can't
Header()
return the error? Inspection in the debugger shows that it reads the error code and message headers out of the frame, but short-circuits because the stream has terminated and internal assignsnoHeaders
. I just want access to the state that is buried in there (there was an error) without having to resort to trying to recv with a timeout.The text was updated successfully, but these errors were encountered: