Unary callback executed multiple times on gRPC error
See original GitHub issueI notice on HTTP/1.1 200 responses with a valid gRPC error that the callback is being executed three times. I believe it’s a result of having a non-OK status code, which leads to executing the callback twice on “status” events and once more on the “error” event in grpcwebclientbase.js
.
I found this to be surprising behavior (I expected at most a single non-null error callback), and since the callback is a required parameter I either have to use a local variable to track whether a non-null error has been previously encountered to prevent triggering error logic multiple times or pass in no-op callback and use the returned ClientReadableStream
object.
Example server code (Go):
func (s *server) Foo(context.Context, *foo.FooRequest) (*foo.FooResponse, error) {
return nil, status.Error(codes.Unimplemented, "unimplemented")
}
Example client code (Typescript):
let client = new FooClient("http://localhost:8888");
let req = new FooRequest();
client.foo(req, null, function(err, resp) {
console.log(err);
console.log(resp);
console.trace();
});
Console output:
{code: 12, message: "unimplemented"}
null
[ stack trace where "status" callback is triggered ]
{code: 12, message: "unimplemented"}
null
[ stack trace where "status" callback is triggered ]
{code: 12, message: "unimplemented"}
null
[ stack trace where "error" callback is triggered ]
I’m curious whether this is intended behavior or not (the double-status event in particular seems odd).
If not, I’ve got a few ideas:
- Make the callback an optional parameter
- Remove the callback entirely to support/force a consistent coding approach (i.e., same as streaming)
- Don’t execute the callback for status updates (i.e., only execute on “data” or “error”)
- Call the callback at most once on the first non-OK status/error response (whichever comes first)
Environment details:
- protoc-gen-grpc-web-1.0.6-darwin-x86_64
- protoc 3.7.1
--js_out=import_style=commonjs:$OUT
--grpc-web_out=import_style=typescript,mode=grpcweb:$OUT
- “google-protobuf”: “^3.10.0-rc.1”
- “grpc-web”: “^1.0.6”
- Server using
github.com/improbable-eng/grpc-web/go/grpcweb
Issue Analytics
- State:
- Created 4 years ago
- Reactions:5
- Comments:7
I tested locally against HEAD (192fef8909dcbc0c9889c348ec092ecf657c62e8) and while the behavior has changed, I still feel it’s confusing as an end user.
Sample code:
1.0.6 behavior:
HEAD behavior:
We now get one less
status
callback and the order oferror
andstatus
are swapped. Using a callback still results in it firing twice on errors as opposed to three times.I also noticed that mixing/matching
stream.on()
with the callback results in “hijacking” the events and prevents the callback being fired (e.g., registeringstream.on("status", ...)
will mean the callback will not get called on status updates). This was also surprising to me.While I’m unblocked for my own project (I pass in no-op callbacks and exclusively use
stream.on("error", ...)
andstream.on("data", ...)
), this seems less than ideal for newcomers to grpc-web.Do you have an opinion on whether this is by design? Happy to contribute code, tests, documentation to clarify!
On 01 May 2020 I steel have the issue.