This is an automated email from the ASF dual-hosted git repository.
xuanwo pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-opendal.git
The following commit(s) were added to refs/heads/main by this push:
new ae6f6716 fix(service/s3): set retryable on batch (#2171)
ae6f6716 is described below
commit ae6f67166e8b2a28cc9a2377654c884d1b09101a
Author: xyJi <[email protected]>
AuthorDate: Mon May 1 13:16:41 2023 +0800
fix(service/s3): set retryable on batch (#2171)
* fix(service/s3): set retryable on batch
* set retryable on batch
* add more retryable errors
Signed-off-by: Ji-Xinyou <[email protected]>
* *
Signed-off-by: Ji-Xinyou <[email protected]>
---------
Signed-off-by: Ji-Xinyou <[email protected]>
---
core/src/services/s3/backend.rs | 14 ++++++++++----
core/src/services/s3/error.rs | 38 +++++++++++++++++++++++++++++---------
2 files changed, 39 insertions(+), 13 deletions(-)
diff --git a/core/src/services/s3/backend.rs b/core/src/services/s3/backend.rs
index 9b2c13b3..d4c54b5f 100644
--- a/core/src/services/s3/backend.rs
+++ b/core/src/services/s3/backend.rs
@@ -37,6 +37,7 @@ use reqsign::AwsV4Signer;
use super::core::*;
use super::error::parse_error;
+use super::error::parse_s3_error_code;
use super::pager::S3Pager;
use super::writer::S3Writer;
use crate::ops::*;
@@ -1129,10 +1130,15 @@ impl Accessor for S3Backend {
for i in result.error {
let path = build_rel_path(&self.core.root, &i.key);
- batched_result.push((
- path,
- Err(Error::new(ErrorKind::Unexpected, &format!("{i:?}"))),
- ));
+ // set the error kind and mark temporary if retryable
+ let (kind, retryable) =
+
parse_s3_error_code(i.code.as_str()).unwrap_or((ErrorKind::Unexpected, false));
+ let mut err = Error::new(kind, &format!("{i:?}"));
+ if retryable {
+ err = err.set_temporary();
+ }
+
+ batched_result.push((path, Err(err)));
}
Ok(RpBatch::new(batched_result))
diff --git a/core/src/services/s3/error.rs b/core/src/services/s3/error.rs
index 56cdd49f..eb943cb3 100644
--- a/core/src/services/s3/error.rs
+++ b/core/src/services/s3/error.rs
@@ -58,16 +58,8 @@ pub async fn parse_error(resp: Response<IncomingAsyncBody>)
-> Result<Error> {
.map(|s3_err| (format!("{s3_err:?}"), Some(s3_err)))
.unwrap_or_else(|_| (String::from_utf8_lossy(&bs).into_owned(), None));
- // All possible error code:
<https://docs.aws.amazon.com/AmazonS3/latest/API/ErrorResponses.html#ErrorCodeList>
if let Some(s3_err) = s3_err {
- (kind, retryable) = match s3_err.code.as_str() {
- // > Your socket connection to the server was not read from
- // > or written to within the timeout period."
- //
- // It's Ok for us to retry it again.
- "RequestTimeout" => (ErrorKind::Unexpected, true),
- _ => (kind, retryable),
- }
+ (kind, retryable) =
parse_s3_error_code(s3_err.code.as_str()).unwrap_or((kind, retryable));
}
let mut err = Error::new(kind, &message).with_context("response",
format!("{parts:?}"));
@@ -79,6 +71,34 @@ pub async fn parse_error(resp: Response<IncomingAsyncBody>)
-> Result<Error> {
Ok(err)
}
+/// Returns the Errorkind of this code and whether the error is retryable.
+/// All possible error code:
<https://docs.aws.amazon.com/AmazonS3/latest/API/ErrorResponses.html#ErrorCodeList>
+pub fn parse_s3_error_code(code: &str) -> Option<(ErrorKind, bool)> {
+ match code {
+ // > Your socket connection to the server was not read from
+ // > or written to within the timeout period."
+ //
+ // It's Ok for us to retry it again.
+ "RequestTimeout" => Some((ErrorKind::Unexpected, true)),
+ // > An internal error occurred. Try again.
+ "InternalError" => Some((ErrorKind::Unexpected, true)),
+ // > A conflicting conditional operation is currently in progress
+ // > against this resource. Try again.
+ "OperationAborted" => Some((ErrorKind::Unexpected, true)),
+ // > Please reduce your request rate.
+ //
+ // It's Ok to retry since later on the request rate may get reduced.
+ "SlowDown" => Some((ErrorKind::RateLimited, true)),
+ // > Service is unable to handle request.
+ //
+ // ServiceUnavailable is considered a retryable error because it
typically
+ // indicates a temporary issue with the service or server, such as
high load,
+ // maintenance, or an internal problem.
+ "ServiceUnavailable" => Some((ErrorKind::Unexpected, true)),
+ _ => None,
+ }
+}
+
#[cfg(test)]
mod tests {
use super::*;