2013-06-21 48 views
1

雖然在很多月的時間裏它的工作基本上完美無缺,但我現在無法將(低級別)分段上傳到Amazon S3。在最後一天左右,它開始失敗。我有一個80多個文件上傳的隊列,在大約60個文件之後才能正常上傳,然後失敗的次數往往比成功的次數多。從那以後,即使單個文件隊列也失敗了。成功上傳每個零件後,S3 CompleteMultipartUpload失敗

我使用的文檔基本上與文檔中低級別分段上傳示例中的代碼相同,只是使用了do-while循環,如果失敗,它將重試上傳單個部分。只有成功的部分上傳被添加到列表中,後者作爲CompleteMultipartUploadRequest的一部分添加。

儘管沒有任何部件上傳失敗,只有在所有部件上傳後發送的CompleteMultipartUploadRequest。這是我在每次失敗時看到的唯一例外,並且始終源於CompleteMultipartUpload請求。

我甚至將CompleteMultipartUpload對象的創建和請求封裝在一個循環中,以防S3是「準備就緒」將部件連接在一起的問題,但即使是具有明顯時間延遲的漸進退避期也沒有幫助。

Exception: Maximum number of retry attempts reached : 3 
Exception: at Amazon.S3.AmazonS3Client.pauseOnRetry(Int32 retries, Int32 maxRetries, HttpStatusCode status, String requestAddr, WebHeaderCollection headers, Exception cause) 
    at Amazon.S3.AmazonS3Client.handleRetry(S3Request userRequest, HttpWebRequest request, WebHeaderCollection respHdrs, Int64 orignalStreamPosition, Int32 retries, HttpStatusCode statusCode, Exception cause) 
    at Amazon.S3.AmazonS3Client.getResponseCallback[T](IAsyncResult result) 
    at Amazon.S3.AmazonS3Client.endOperation[T](IAsyncResult result) 
    at Amazon.S3.AmazonS3Client.EndCompleteMultipartUpload(IAsyncResult asyncResult) 
    at Amazon.S3.AmazonS3Client.CompleteMultipartUpload(CompleteMultipartUploadRequest request) 

這是以下的代碼。有什麼可能是錯誤的建議?

// List to store upload part responses. 
List<UploadPartResponse> uploadResponses = new List<UploadPartResponse>(); 
List<PartETag> uploadPartETags = new List<PartETag>(); 

// 1. Initialize. 
InitiateMultipartUploadRequest initiateRequest = new InitiateMultipartUploadRequest() 
    .WithBucketName(s3bucketName) 
    .WithKey(key); 
initResponse = s3Client.InitiateMultipartUpload(initiateRequest); 
bwLogUploadFiles("multipart upload ID " + initResponse.UploadId); 


// 2. Upload Parts. 
uploadFileSize = new FileInfo(sourceFilepath).Length; 
uploadTypicalPartSize = PART_SIZE_DEFAULT;  // 5 MB 

uploadNumParts = uploadFileSize/uploadTypicalPartSize + 1; 
Debug.WriteLine("# of parts: " + uploadNumParts); 

int retryCount = 0; 

long filePosition = 0; 
for (int i = 1; filePosition < uploadFileSize; i++) 
{ 
    uploadCurrentPart = i; 

    //long percent = (100 * filePosition)/uploadFileSize; 
    //reportUploadProgress((int)percent, filePosition); 

    bwLogUploadFiles("upload part " + i + " of " + uploadNumParts); 

    retryCount = 0; 

    // make the part size exactly equal to the lesser of the part size (5MB) or the remaining amount 
    //long tmpPartSize = Math.Min(uploadTypicalPartSize, (uploadFileSize - filePosition));  

    // per documentation examples, just make part size the same every time, even if remaining file length is bigger 
    long tmpPartSize = uploadTypicalPartSize; 

    // Create request to upload a part. 
    UploadPartRequest uploadRequest = new UploadPartRequest() 
     .WithBucketName(s3bucketName) 
     .WithKey(key) 
     .WithUploadId(initResponse.UploadId) 
     .WithPartNumber(i) 
     .WithPartSize(tmpPartSize) 
     .WithFilePosition(filePosition) 
     .WithFilePath(sourceFilepath) 
     .WithSubscriber(transferUtilityUploadSubscriberLowLevel) 
     .WithReadWriteTimeout(PART_TIMEOUT) 
     .WithTimeout(UPLOAD_TIMEOUT); 


    UploadPartResponse resp = null; 

    // repeat the part upload until it succeeds. 
    Boolean anotherPass; 
    do 
    { 
     anotherPass = false; // assume everythings ok 
     try { 
      // Upload part 
      resp = s3Client.UploadPart(uploadRequest); 

      // add response to our list. 
      uploadResponses.Add(resp); 

      // only creating PartETag and adding to a list for testing a different way of constructing the CompleteMultipartUploadRequest at the end. 
      PartETag petag = new PartETag(resp.PartNumber, resp.ETag); 
      uploadPartETags.Add(petag); 

      bwLogUploadFiles("upload part " + resp.PartNumber + " of " + uploadNumParts + " success. Part ETag "+resp.ETag); 
     } 
     catch (Exception e) 
     { 
      anotherPass = true; // repeat 
      retryCount++; 
      Debug.WriteLine(e.Message +": retry part #" + i); 
      bwLogUploadFiles("upload part " + i + " of " + uploadNumParts + " FAIL. Will retry if attempt #" + retryCount + "<"uploading part #"+i+" couldn't upload after "+MAX_RETRIES+" attempts. Upload failed"); 

    filePosition += tmpPartSize; 


} 
//reportUploadProgress(100, uploadFileSize); 


// Step 3: complete. 

Boolean retryCompleteRequest = true; 
Boolean completeSuccess = false; 
int completeAttempts = 0; 
const int delaySecondsMultiple = 3; 


// retry a few times in case it's just a timing or S3 sync or readiness issue. Maybe giving it some time make following the part uploads will do the trick 
do 
{ 
    retryCompleteRequest = false; 
    try 
    { 
     bwLogUploadFiles("complete the multipart upload, attempt #"+(completeAttempts+1)); 
     if (completeAttempts >0) 
     { 
      bwLogUploadFiles("delay " + (delaySecondsMultiple * completeAttempts) + " seconds"); 
      Thread.Sleep(delaySecondsMultiple * 1000 * completeAttempts);  // 
     } 

     Debug.WriteLine("now complete the Mulitpart Upload Request"); 
     CompleteMultipartUploadRequest completeRequest = new CompleteMultipartUploadRequest() 
      .WithBucketName(s3bucketName) 
      .WithKey(key) 
      .WithUploadId(initResponse.UploadId) 
      //.WithPartETags(uploadResponses) // historically we've been attaching a List<UploadPartResponse> 
      .WithPartETags(uploadPartETags); // for testing we're trying List<PartETag> 

     CompleteMultipartUploadResponse completeUploadResponse = s3Client.CompleteMultipartUpload(completeRequest); 
     completeSuccess = true; 
    } 
    catch (Exception e) 
    { 
     completeAttempts++; 
     retryCompleteRequest = true; 

     Console.WriteLine("Exception occurred: {0}", e.Message); 
     Console.WriteLine(e.StackTrace); 

     bwLogUploadFiles("Exception: " + e.Message); 
     bwLogUploadFiles("Exception: " + e.StackTrace); 
    } 
} 
while (retryCompleteRequest && completeAttempts < MAX_RETRIES); 

回答

0

我知道這是不合邏輯的,但你可以嘗試這個例外。 嘗試將s3Client協議顯式設置爲HTTP。