denoland / deno

A modern runtime for JavaScript and TypeScript.
https://deno.com
MIT License
97.91k stars 5.39k forks source link

Break in gRPC connection doesn't emit any errors #24845

Closed garethj2 closed 1 month ago

garethj2 commented 3 months ago

Version: Deno 1.45.5

I can create a gRPC client connection to a gRPC server. If I then shutdown the server with the client still running, the client gets the following error in the output...

Unhandled rejection in extension worker: Error: stream error received: not a result of an error Promise {
  <rejected> Error: stream error received: not a result of an error
    at node:http2:735:50
    at ClientHttp2Stream._read (node:http2:761:7)
    at ClientHttp2Stream.Readable.read (ext:deno_node/_stream.mjs:2996:16)
    at maybeReadMore_ (ext:deno_node/_stream.mjs:3092:16)
    at processTicksAndRejections (ext:deno_node/_next_tick.ts:33:15)
    at runNextTicks (ext:deno_node/_next_tick.ts:71:3)
    at eventLoopTick (ext:core/01_core.js:175:21)
}

No errors are raised on client event stream. Ideally the client should be notified if there's an underlying connection issue. Seems like this is unhandled.

TobyEalden commented 1 month ago

I'm getting a similar error, using:

deno 2.0.0 (stable, release, aarch64-apple-darwin)
v8 12.9.202.13-rusty
typescript 5.6.2

I have a C++ grpc server and some client code written in js using https://github.com/grpc/grpc-node.

Everything works as expected when running under node v18.18.2.

When using Deno, the server successfully receives a valid request for a unary call, and sends back a response. The client then bombs out with this output (GRPC logging enabled):

D 2024-10-11T10:59:17.311Z | v1.12.2 14867 | subchannel_call | [3] Received server headers:
        :status: 200
        content-type: application/grpc
        grpc-encoding: deflate
        grpc-accept-encoding: identity, deflate, gzip

D 2024-10-11T10:59:17.323Z | v1.12.2 14867 | load_balancing_call | [2] Received metadata
D 2024-10-11T10:59:17.324Z | v1.12.2 14867 | retrying_call | [1] Received metadata from child [2]
D 2024-10-11T10:59:17.324Z | v1.12.2 14867 | retrying_call | [1] Committing call [2] at index 0
D 2024-10-11T10:59:17.325Z | v1.12.2 14867 | resolving_call | [0] Received metadata
D 2024-10-11T10:59:17.327Z | v1.12.2 14867 | subchannel_call | [3] receive HTTP/2 data frame of length 774
D 2024-10-11T10:59:17.327Z | v1.12.2 14867 | subchannel_call | [3] parsed message of length 774
D 2024-10-11T10:59:17.327Z | v1.12.2 14867 | subchannel_call | [3] pushing to reader message of length 774
D 2024-10-11T10:59:17.328Z | v1.12.2 14867 | load_balancing_call | [2] Received message
D 2024-10-11T10:59:17.328Z | v1.12.2 14867 | retrying_call | [1] Received message from child [2]
D 2024-10-11T10:59:17.328Z | v1.12.2 14867 | resolving_call | [0] Received message
D 2024-10-11T10:59:17.331Z | v1.12.2 14867 | resolving_call | [0] Finished filtering received message
D 2024-10-11T10:59:17.333Z | v1.12.2 14867 | resolving_call | [0] startRead called
D 2024-10-11T10:59:17.333Z | v1.12.2 14867 | retrying_call | [1] startRead called
D 2024-10-11T10:59:17.333Z | v1.12.2 14867 | load_balancing_call | [2] startRead called
error: Uncaught (in promise) Error: stream error received: not a result of an error
    at node:http2:824:50
    at ClientHttp2Stream._read (node:http2:850:7)
    at ClientHttp2Stream.Readable.read (ext:deno_node/_stream.mjs:2561:16)
    at maybeReadMore_ (ext:deno_node/_stream.mjs:2657:16)
    at processTicksAndRejections (ext:deno_node/_next_tick.ts:36:15)
    at runNextTicks (ext:deno_node/_next_tick.ts:75:3)
    at eventLoopTick (ext:core/01_core.js:182:21)
❯

Let me know if you need any more info or how I can help with troubleshooting this.

TobyEalden commented 1 month ago

After looking into this in more detail, it seems specific (in my case) to grpc servers built using C++ closing the server side of a bidirectional stream while the client is still connected.

This is evident in a large C++ grpc codebase that I maintain, but I was able to reproduce it using the RouteGuide example in the grpc repo.

To reproduce the issue, see the repo https://github.com/TobyEalden/deno-issue-24845.