grpc/grpc-dotnet

Is `WriteResponseHeadesAsync` supposed to send the headers immediately?

bosh-3shape opened this issue · 2 comments

Hello.
My question consists of two parts: the actual question and the context behind it. It might be the case that the context is important as much as the question itself :)

Context
I'm debugging an issue: I observe that server-side WriteResponseHeadesAsync does not send the response headers immediately in certain cases.
My application consists of two parts: client and server. The client side is using C-based gRPC client (I can't switch to .NET implementation yet), and the ASP.NET gRPC server (Kestrel).

For some of the calls, the client application expects the header exchange to happen before proceeding with messages. Everything works as expected, when the client connects to the server.

However, if I add a YARP-based reverse proxy in between the client and the server, the calls that expect the header exchange stop working. However, if I send a "dummy" message right after WriteResponseHeadesAsync, the client receives the headers just fine. This somehow hints to the fact that the headers are not sent immediately after calling WriteResponseHeadesAsync.
This points to a different behaviour of C-based client implementation and .NET-based implementation (coming from YARP).

This is a strange situation, and some search brought me to this issue: #1620. Unfortunately, the author did not follow up on the question asked.
Nevertheless, it seems like I experience a very similar issue: (1) I can see a different behaviour of the server depending on the client used and (2) I cannot explain the reasons for such differences server-side.

As suggested by the comment in the (#1620), I looked at the unit tests, and I could not find a unit test that tests that the headers are successfully sent alone; all the tests I could find actually send a message after filling the headers (e.g. here).
The test linked to above also hints that the headers are not sent immediately.

The implementation (here) also suggests that the headers are not sent if there is no response body.

If I understand the gRPC response spec correctly (here), the response can have zero Length-Prefixed-Message items, which is in fact the DATA to be sent back.
Also here, nothing suggests that the server must send the response body to actually send headers.

The Question
(actually, several questions)

  1. Is WriteResponseHeadesAsync method (on the server side) supposed to send the response headers immediately, even if there are no following response messages? In other words, if I call await WriteResponseHeadesAsync(new Metadata()), is the client supposed to receive the headers after this call is awaited?
  2. Why is there a difference in the server-side behaviour, depending on the client used?
  3. Is this an actual bug in the server-side gRPC .NET?