aboutsummaryrefslogtreecommitdiff
path: root/src/zenutil/cloud/s3client.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/zenutil/cloud/s3client.cpp')
-rw-r--r--src/zenutil/cloud/s3client.cpp32
1 files changed, 32 insertions, 0 deletions
diff --git a/src/zenutil/cloud/s3client.cpp b/src/zenutil/cloud/s3client.cpp
index f8bed92da..ab80cfcc7 100644
--- a/src/zenutil/cloud/s3client.cpp
+++ b/src/zenutil/cloud/s3client.cpp
@@ -148,11 +148,31 @@ namespace {
return true;
}
+ /// True if the response indicates S3 throttling (503 SlowDown / ServiceUnavailable / 429).
+ /// Code is checked on both the HTTP status and the XML error code so we catch proxies that
+ /// return 200 with a SlowDown body.
+ bool IsS3Throttled(const HttpClient::Response& Response, std::string_view ErrorCode)
+ {
+ const int Status = static_cast<int>(Response.StatusCode);
+ if (Status == 503 || Status == 429)
+ {
+ return true;
+ }
+ if (ErrorCode == "SlowDown" || ErrorCode == "ServiceUnavailable" || ErrorCode == "ThrottlingException" ||
+ ErrorCode == "RequestLimitExceeded" || ErrorCode == "TooManyRequests")
+ {
+ return true;
+ }
+ return false;
+ }
+
/// Build a human-readable error message for a failed S3 response. When the response body
/// contains an S3 `<Error>` element, the Code and Message fields are included in the string
/// so transient 4xx/5xx failures (SignatureDoesNotMatch, AuthorizationHeaderMalformed, etc.)
/// show up in logs instead of being swallowed. Falls back to the generic HTTP/transport
/// message when no XML body is available (HEAD responses, transport errors).
+ /// Also emits a distinct `S3 THROTTLED` warning when the response indicates throttling so
+ /// callers can grep for it without parsing combined error text.
std::string S3ErrorMessage(std::string_view Prefix, const HttpClient::Response& Response)
{
if (!Response.Error.has_value() && Response.ResponsePayload)
@@ -164,9 +184,21 @@ namespace {
{
ExtendableStringBuilder<256> Decoded;
DecodeXmlEntities(Message, Decoded);
+ if (IsS3Throttled(Response, Code))
+ {
+ ZEN_WARN("S3 THROTTLED [{}] status={} code='{}' message='{}'",
+ Prefix,
+ static_cast<int>(Response.StatusCode),
+ Code,
+ Decoded.ToView());
+ }
return fmt::format("{}: HTTP status ({}) {} - {}", Prefix, static_cast<int>(Response.StatusCode), Code, Decoded.ToView());
}
}
+ if (IsS3Throttled(Response, {}))
+ {
+ ZEN_WARN("S3 THROTTLED [{}] status={} (no XML body)", Prefix, static_cast<int>(Response.StatusCode));
+ }
return Response.ErrorMessage(Prefix);
}