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::*;

Reply via email to