Как указать, что код состояния HTTP 304 (NotModified) не является условием ошибки внутри API Amazon S3 GetObject? - PullRequest
7 голосов
/ 11 октября 2011

Фон

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

Подход

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

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

Проблема

Проблема, однако, заключается вчто при вызове AmazonS3.GetObject (или его асинхронном эквиваленте) API Amazon .Net фактически видит код состояния HTTP 304 (NotModified) как ошибку и повторяет запрос get три раза, а затем, наконец, выдает Amazon.S3.AmazonS3Exception: Maximum number of retry attempts reached : 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)<---

1 Ответ

3 голосов
/ 13 октября 2011

Я также разместил этот вопрос на форуме разработчиков Amazon и получил ответ от официального сотрудника AWS:

После изучения этого мы понимаем проблему, но мы ищем за отзывы о том, как лучше всего с этим справиться.

Первый подход - вернуть эту операцию со свойством на GetObjectResponse, указывающий, что объект не был возвращен или установлен поток вывода на ноль. Это было бы чище, но это создает легкое разрушительное поведение для тех, кто полагается на исключение выбрасывается, хотя и после 3 попыток. Было бы также несовместимо с операцией CopyObject, которая бросает исключение без всякой сумасшедшей повторной попытки.

Другой вариант - мы генерируем исключение, похожее на CopyObject, которое держит нас последовательными и без серьезных изменений, но это сложнее код против.

Если у кого-то есть мнение о том, как с этим справиться, ответьте на эта тема.

Norm

Я уже добавил свои мысли в ветку, если кто-то еще заинтересован в участии, вот ссылка:

AmazonS3.GetObject видит HTTP 304 (NotModified) как ошибку. Способ это разрешить?


ПРИМЕЧАНИЕ: Когда это будет решено Amazon, я обновлю свой ответ, чтобы отразить результат.


ОБНОВЛЕНИЕ: (2012-01-24) Все еще в ожидании дополнительной информации от Amazon.

ОБНОВЛЕНИЕ: (2018-12-06) это было исправлено в AWS SDK 1.5.20 в 2013 году https://forums.aws.amazon.com/thread.jspa?threadID=77995&tstart=0

...