Fix gRPC terminal and response boundaries - #467
Conversation
Treat an already-completed successful response as an idempotent client-streaming half-close, and translate an early failed response through the existing metadata-rich RPC exception boundary. This preserves the documented writesDone-then-wait sequence even when the receiver wins the connection-send race. Stop lazy frame decoding as soon as buffered response limits are exhausted. Account streamed metadata using only the headers the Swoole response bridge emits, and remove the dead reserved content-length state. Add deterministic regressions for early terminal responses, blocked half-closes, decoder exhaustion, and exact streamed metadata limits. Link the ported gRPC and Object Pools guides, and record the completed targeted corrections and cross-package revalidation in the audit ledger.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (12)
💤 Files with no reviewable changes (3)
📝 WalkthroughWalkthroughThe PR corrects gRPC client terminal handling, stops stream decoding after buffer exhaustion, removes reserved streamed content-length accounting, adds regression coverage, and updates audit and Boost documentation navigation. ChangesgRPC lifecycle corrections
Estimated code review effort: 3 (Moderate) | ~25 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Greptile SummaryThe PR corrects terminal-state handling for client-streaming calls, stops response decoding at the configured buffer boundary, and aligns streamed metadata accounting with emitted HTTP/2 headers.
Confidence Score: 5/5The PR appears safe to merge, with the changed terminal, decoding, and metadata boundaries consistent with their callers and transport behavior. The half-close logic preserves completed statuses across the receiver race, decoding terminates at the first buffer failure, and streamed metadata sizing now matches the response bridge that removes content-length before emission.
|
| Filename | Overview |
|---|---|
| src/grpc/src/Client/Call.php | Separates successful terminal completion from write misuse and preserves terminal RPC failures across half-close races. |
| src/grpc/src/Client/StreamState.php | Stops lazy frame iteration immediately after recording response-buffer exhaustion. |
| src/grpc/src/Server/ResponseFactory.php | Restricts content-length metadata accounting to unary responses, matching the transport bridge’s emitted headers. |
| src/grpc/src/Server/GrpcStreamedResponse.php | Removes reservation state that is no longer part of streamed metadata accounting. |
| tests/Grpc/ClientStreamingCallTest.php | Adds deterministic coverage for early success, early RPC failure, and receiver-versus-half-close races. |
| tests/Grpc/StreamStateTest.php | Verifies that buffer exhaustion prevents later malformed frames from being decoded. |
| tests/Grpc/ResponseFactoryTest.php | Verifies exact streamed metadata limits against headers actually emitted by the transport. |
| src/boost/docs/documentation.md | Adds navigation links for the existing Object Pools and gRPC guides. |
Reviews (1): Last reviewed commit: "Merge remote-tracking branch 'origin/0.4..." | Re-trigger Greptile
Summary
This PR fixes three correctness boundaries in the gRPC package and restores navigation to two ported guides.
Client-streaming calls now accept a terminal response that arrives before the request is half-closed. A successful response makes
writesDone()an idempotent operation, while a failed response is translated through the existing metadata-richRpcExceptionboundary. This also covers the race where the receiver completes and releases the stream while the half-close is waiting for the connection send boundary.Response decoding now stops immediately after the configured message or byte buffer is exhausted. The previous implementation recorded
ResourceExhaustedbut continued advancing the lazy frame decoder, allowing later malformed input to replace the intended terminal result and performing unnecessary work after the call had already failed.Streamed response metadata is now measured against the headers the Swoole response bridge actually emits. Streamed responses do not send
content-length, so reserving bytes for it rejected valid metadata at the configured boundary. The unused reservation state and accessor are removed.The Boost documentation index now links the existing Object Pools and gRPC guides. The audit dependency index and ledger record the targeted corrections and completed cross-package revalidation.
Behavior
The documented client-streaming sequence now works even when the server responds early:
Non-OK terminal responses still surface as
RpcExceptionwith the call method, target, status, and metadata. Attempts to write a new message after completion retain the existingLogicExceptionbehavior.There are no public signature, generated-client, routing, configuration, pooling, or transport changes.
Implementation
content-lengthonly for unary responses, matching actual response emission.The normal request path gains no lock, retry, yield, serialization layer, network round trip, registry, or worker-retained state. Buffer exhaustion now performs less work, and metadata accounting removes unused state.
Testing
composer fix.Summary by CodeRabbit
Bug Fixes
Documentation
Tests