Как указать, что код состояния HTTP 304 (NotModified) не является условием ошибки в API Amazon S3 GetObject?

Предпосылки

Я пытаюсь использовать S3 как «бесконечный» большой уровень кэширования для некоторых «довольно» статических XML-документов. Я хочу убедиться, что клиентское приложение (которое будет работать на тысячах машин одновременно и запрашивать XML-документы много раз в час) загружает эти XML-документы только в том случае, если их содержимое изменилось с момента последней загрузки клиентским приложением.

Подход

В Amazon S3 мы можем использовать для этого HTTP ETAG. По умолчанию для объектов Amazon S3 ETAG установлен на хэш MD5 объекта.

Затем мы можем указать хэш MD5 XML-документа внутри Свойство GetObjectRequest.ETagToNotMatch . Это гарантирует, что при вызове AmazonS3.GetObject (или, в моем случае, асинхронной версии AmazonS3.BeginGetObject и и .EndGetObject ), что если запрашиваемый документ ed имеет тот же хеш MD5, что и в GetObjectRequest.ETagToNotMatch , затем S3 автоматически возвращает код состояния HTTP 304 (NotModified), и фактическое содержимое XML-документа не загружено.

Проблема

Однако проблема заключается в том, что при вызове AmazonS3.GetObject (или его асинхронного эквивалента) API Amazon .Net фактически видит код состояния HTTP 304 (NotModified) как ошибку и повторяет попытку запрос получения три раза, а затем, наконец, выдает исключение Amazon.S3.AmazonS3Exception: Достигнуто максимальное количество попыток повтора: 3 .

Очевидно, я мог бы изменить эту реализацию, чтобы использовать AmazonS3.GetObjectMetaData , а затем сравнить ETAG и использовать AmazonS3.GetObject , если они не совпадают, но тогда есть два запроса к S3 вместо одного, если файл устарел. Я бы предпочел иметь один запрос независимо от того, нужно ли загружать XML-документ или нет.

Есть идеи? Это ошибка или я что-то упускаю? Есть ли хоть какой-то способ уменьшить количество повторных попыток до одного и «обработать» исключение (хотя мне кажется, что этот маршрут «фу»).

Реализация

Я использую AWS SDK для .NET (версия 1.3.14).

Вот моя реализация (немного уменьшенная, чтобы она была короче):

public Task<GetObjectResponse> DownloadString(string key, string etag = null) {

    var request = new GetObjectRequest { Key = key, BucketName = Bucket };

    if (etag != null) {
        request.ETagToNotMatch = etag;
    }

    var task = Task<GetObjectResponse>.Factory.FromAsync(_s3Client.BeginGetObject, _s3Client.EndGetObject, request, null);

    return task;
}

Затем я называю это так:

var dlTask          = s3Manager.DownloadString("new one", "d7db7bc318d6eb9222d728747879b52e");
var responseTasks   = new[]
    {
        dlTask.ContinueWith(x => _log.Error("Error downloading string.", x.Exception), TaskContinuationOptions.OnlyOnFaulted),
        dlTask.ContinueWith(x => _log.Warn("Downloading string was cancelled."), TaskContinuationOptions.OnlyOnCanceled),
        dlTask.ContinueWith(x => _log.Info(string.Format("Done with download: {0}", x.Result.ETag)), TaskContinuationOptions.OnlyOnRanToCompletion)
    };

try {
    Task.WaitAny(responseTasks);
} catch (AggregateException aex) {
    _log.Error("Error while processing download string.", aex);
}

_log.Info("Exiting...");

Это затем производит следующий вывод файла журнала:

2011-10-11 13:21:20,376 [11] INFO  Amazon.S3.AmazonS3Client - Received response for GetObject (id 2ee99002-d148-4572-b19b-29259534f48f) with status code NotModified in 00:00:01.6140812.
2011-10-11 13:21:20,385 [11] INFO  Amazon.S3.AmazonS3Client - Request for GetObject is being redirect to https://s3.amazonaws.com/x/new%20one.
2011-10-11 13:21:20,789 [11] INFO  Amazon.S3.AmazonS3Client - Retry number 1 for request GetObject.
2011-10-11 13:21:22,329 [11] INFO  Amazon.S3.AmazonS3Client - Received response for GetObject (id 2ee99002-d148-4572-b19b-29259534f48f) with status code NotModified in 00:00:01.1400356.
2011-10-11 13:21:22,329 [11] INFO  Amazon.S3.AmazonS3Client - Request for GetObject is being redirect to https://s3.amazonaws.com/x/new%20one.
2011-10-11 13:21:23,929 [11] INFO  Amazon.S3.AmazonS3Client - Retry number 2 for request GetObject.
2011-10-11 13:21:26,508 [11] INFO  Amazon.S3.AmazonS3Client - Received response for GetObject (id 2ee99002-d148-4572-b19b-29259534f48f) with status code NotModified in 00:00:00.9790314.
2011-10-11 13:21:26,508 [11] INFO  Amazon.S3.AmazonS3Client - Request for GetObject is being redirect to https://s3.amazonaws.com/x/new%20one.
2011-10-11 13:21:32,908 [11] INFO  Amazon.S3.AmazonS3Client - Retry number 3 for request GetObject.
2011-10-11 13:21:40,604 [11] INFO  Amazon.S3.AmazonS3Client - Received response for GetObject (id 2ee99002-d148-4572-b19b-29259534f48f) with status code NotModified in 00:00:01.2950718.
2011-10-11 13:21:40,605 [11] INFO  Amazon.S3.AmazonS3Client - Request for GetObject is being redirect to https://s3.amazonaws.com/x/new%20one.
2011-10-11 13:21:40,621 [11] ERROR Amazon.S3.AmazonS3Client - Error for GetResponse
Amazon.S3.AmazonS3Exception: Maximum number of retry attempts reached : 3
   at Amazon.S3.AmazonS3Client.pauseOnRetry(Int32 retries, Int32 maxRetries, HttpStatusCode status, String requestAddr, WebHeaderCollection headers, Exception cause)
   at Amazon.S3.AmazonS3Client.handleHttpResponse[T](S3Request userRequest, HttpWebRequest request, HttpWebResponse httpResponse, Int32 retries, TimeSpan lengthOfRequest, T& response, Exception& cause, HttpStatusCode& statusCode)
   at Amazon.S3.AmazonS3Client.getResponseCallback[T](IAsyncResult result)
2011-10-11 13:21:40,635 [10] INFO  Example.Program - Exiting...
2011-10-11 13:21:40,638 [19] ERROR Example.Program - Error downloading string.
System.AggregateException: One or more errors occurred. ---> Amazon.S3.AmazonS3Exception: Maximum number of retry attempts reached : 3
   at Amazon.S3.AmazonS3Client.pauseOnRetry(Int32 retries, Int32 maxRetries, HttpStatusCode status, String requestAddr, WebHeaderCollection headers, Exception cause)
   at Amazon.S3.AmazonS3Client.handleHttpResponse[T](S3Request userRequest, HttpWebRequest request, HttpWebResponse httpResponse, Int32 retries, TimeSpan lengthOfRequest, T& response, Exception& cause, HttpStatusCode& statusCode)
   at Amazon.S3.AmazonS3Client.getResponseCallback[T](IAsyncResult result)
   at Amazon.S3.AmazonS3Client.endOperation[T](IAsyncResult result)
   at Amazon.S3.AmazonS3Client.EndGetObject(IAsyncResult asyncResult)
   at System.Threading.Tasks.TaskFactory`1.FromAsyncCoreLogic(IAsyncResult iar, Func`2 endMethod, TaskCompletionSource`1 tcs)
   --- End of inner exception stack trace ---
---> (Inner Exception #0) Amazon.S3.AmazonS3Exception: Maximum number of retry attempts reached : 3
   at Amazon.S3.AmazonS3Client.pauseOnRetry(Int32 retries, Int32 maxRetries, HttpStatusCode status, String requestAddr, WebHeaderCollection headers, Exception cause)
   at Amazon.S3.AmazonS3Client.handleHttpResponse[T](S3Request userRequest, HttpWebRequest request, HttpWebResponse httpResponse, Int32 retries, TimeSpan lengthOfRequest, T& response, Exception& cause, HttpStatusCode& statusCode)
   at Amazon.S3.AmazonS3Client.getResponseCallback[T](IAsyncResult result)
   at Amazon.S3.AmazonS3Client.endOperation[T](IAsyncResult result)
   at Amazon.S3.AmazonS3Client.EndGetObject(IAsyncResult asyncResult)
   at System.Threading.Tasks.TaskFactory`1.FromAsyncCoreLogic(IAsyncResult iar, Func`2 endMethod, TaskCompletionSource`1 tcs)<---
7
задан InvertedAcceleration 12 October 2011 в 12:04
поделиться