Remote: stop retrying oversized gRPC messages - #30716
Conversation
Summary: Intent: - Avoid repeated backoff for unchanged UpdateActionResult requests that exceed a remote cache's fixed gRPC receive limit. - Preserve retry behavior for quota, overload, and other RESOURCE_EXHAUSTED failures. Changes: - Recognize exact grpc-go and grpc-java message-size rejection formats only for action cache uploads. - Propagate deterministic size rejections without counting them as remote service failures. - Report an actionable warning and cover recognized, malformed, and ordinary resource exhaustion cases.
|
Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA). View this failed invocation of the CLA check for more information. For the most up to date status, view the checks section at the bottom of the pull request. |
|
✅ Bazel docs preview is ready! Preview URL: https://bazel-pr-30716.mintlify.app/ Updated for |
|
It seems weird to special case go and java implementations. Why not rust or c++? It's also odd that we have typed statuses to decide what to do but are instead sniffing for strings. Perhaps grpc should distinguish between a framework resource exceeded (message size) or an application one (replenishing quota)? |
:(
Added implementation for C++. Rust is not included because its receive-size enforcement incidentally returns |
I've never seen someone use grpc-rust, tonic is what the OSS world mostly uses AFAIK. Which is exactly my point, it doesn't really make sense to enumerate the quirks of a fixed set of implementations :) |
grpc-rust is tonic’s current repository (formerly hyperium/tonic); #1274 changes Tonic’s decoder directly. That being said, I agree this workaround is not ideal. It is the most conservative approach I found, but I’m open to alternatives. |
Summary
RESOURCE_EXHAUSTEDfailures.Motivation
When a gRPC message exceeds the receiver's configured limit, the receiving gRPC implementation may reject it before the application handler runs. Retrying the unchanged message cannot succeed: neither the message bytes nor the receiver's fixed limit changes between attempts. The retries therefore add backoff delay without doing useful work.
gRPC deliberately standardized framework message-size failures as
RESOURCE_EXHAUSTEDin grpc/grpc#10612, the same status applications use for potentially transient failures such as quota exhaustion. The protocol provides no structured subtype that distinguishes these cases; this ambiguity and the lack of a typed alternative were noted in the original discussion.This keeps the existing general treatment of
RESOURCE_EXHAUSTEDas transient. It recognizes only exact, anchored grpc-go, grpc-java, and gRPC C++ message-size formats, avoiding confusion with quota or descriptive server errors. Rust Tonic reports the corresponding declared-size failure asOUT_OF_RANGE, which Bazel already treats as non-retryable.The classification is centralized in
RemoteRetrierand preserves the original gRPC status, description, and trailers.The circuit-breaker treatment follows the precedent discussed in #18583 and implemented in #18662: deterministic request-size failures do not indicate an unhealthy remote-cache service.
This change does not make the RPC succeed; the receiver's limit must be raised or the message reduced. It only avoids retrying a message that cannot succeed under the current limit.
Tests
RESOURCE_EXHAUSTEDremains retryable.