Repository navigation
Description
Is there an existing issue for this?
- I searched open/closed issues and PRs for gRPC backpressure, streaming, buffering and flow control; I did not find an equivalent report.
Current Behavior
ShenyuGrpcClient.invoke() sends CLIENT_STREAMING and BIDI_STREAMING requests by traversing the entire request list:
requestObserver = asyncClientStreamingCall(createCall(callParams), compositeObserver);
requestList.forEach(requestObserver::onNext);
requestObserver.onCompleted();The bidi branch uses the same loop. Neither branch observes ClientCallStreamObserver.isReady() or resumes sending through an onReadyHandler.
grpc-java still provides HTTP/2 transport flow control. However, StreamObserver.onNext() can enqueue a message before the peer can consume it; ignoring readiness can create additional outbound buffering when the backend reads slowly. This is a missing application-level sending policy, not evidence that HTTP/2 flow control is absent or that an OOM has occurred.
The request JSON is already materialized as a list before this loop. A readiness-aware drain would bound additional sending work; it would not by itself bound the original HTTP request body/list.
Expected Behavior
Drain pending client/bidi requests according to gRPC outbound readiness, preserving message order, termination and existing RPC semantics.
Evidence
- Request materialization.
- CLIENT_STREAMING/BIDI_STREAMING send loops.
- grpc-java 1.65.1's
CallStreamObserver.isReady()contract explains that ignoring readiness can cause excessive internal buffering.
Suggested Verification and Acceptance
- Capture the actual client call observer through the supported client-observer lifecycle; use
isReady/onReadyor an equivalent bounded mechanism. - When readiness is false, pause the drain; resume after readiness becomes true, checking readiness again during the callback.
- Preserve order and exactly-once delivery to
onNext; invokeonCompletedonly after pending messages have been submitted. - Stop pending sends on termination/cancellation, and serialize drain work to prevent duplicate sends from reentrant/concurrent readiness callbacks.
- Add deterministic tests that alternate ready/not-ready states, including termination while requests remain. Keep unary/server-streaming behavior unchanged.
- Exercise a slow-reading backend with a large finite request list; record pending work, memory and convergence. Do not replace the loop with an unbounded executor/queue.
Environment and Validation Boundary
Reviewed ShenYu 2.7.2-SNAPSHOT, master 87c22dde7be14c1c3755440a4d8b082a86d10a87, grpc-java 1.65.1. This report is based on source inspection and the installed official grpc-java source. The slow-backend scenario above is proposed validation; no load benchmark or production failure was reproduced.
The separate response-aggregation issue concerns received results and the HTTP response contract. WebSocket forwarding uses a separate reactive receive -> send bridge and is outside this report.
Activity
konlue commentedon Oct 23, 2026
/assign
fix(grpc): drain client and bidi streams according to outbound readin…
fix(grpc): drain client and bidi streams according to outbound readin…