Пакет SDK для службы поиска Azure .net - как использовать FindFailedActionsToRetry?

При использовании пакета SDK для поиска Azure .net при попытке индексирования документов вы можете получить исключение IndexBatchException.

Из документации здесь:

        try
        {
            var batch = IndexBatch.Upload(documents);
            indexClient.Documents.Index(batch);
        }
        catch (IndexBatchException e)
        {
            // Sometimes when your Search service is under load, indexing will fail for some of the documents in
            // the batch. Depending on your application, you can take compensating actions like delaying and
            // retrying. For this simple demo, we just log the failed document keys and continue.
            Console.WriteLine(
                "Failed to index some of the documents: {0}",
                String.Join(", ", e.IndexingResults.Where(r => !r.Succeeded).Select(r => r.Key)));
        }

Как следует использовать e.FindFailedActionsToRetry для создания нового пакета, чтобы повторить попытку индексации для неудачных действий?

Я создал такую ​​функцию:

    public void UploadDocuments<T>(SearchIndexClient searchIndexClient, IndexBatch<T> batch, int count) where T : class, IMyAppSearchDocument
    {
        try
        {
            searchIndexClient.Documents.Index(batch);
        }
        catch (IndexBatchException e)
        {
            if (count == 5) //we will try to index 5 times and give up if it still doesn't work.
            {
                throw new Exception("IndexBatchException: Indexing Failed for some documents.");
            }

            Thread.Sleep(5000); //we got an error, wait 5 seconds and try again (in case it's an intermitent or network issue

            var retryBatch = e.FindFailedActionsToRetry<T>(batch, arg => arg.ToString());
            UploadDocuments(searchIndexClient, retryBatch, count++);
        }
    }

Но я думаю, что это неверно:

var retryBatch = e.FindFailedActionsToRetry<T>(batch, arg => arg.ToString());

person richard    schedule 13.10.2016    source источник


Ответы (2)


Второй параметр FindFailedActionsToRetry с именем keySelector - это функция, которая должна возвращать любое свойство в вашем типе модели, представляющее ваш ключ документа. В вашем примере тип вашей модели неизвестен во время компиляции внутри UploadDocuments, поэтому вам нужно изменить UploadsDocuments, чтобы также принять параметр keySelector и передать его в FindFailedActionsToRetry. Вызывающий UploadDocuments должен указать лямбда, специфичную для типа T. Например, если T - это образец Hotel класса из образца кода в , это article, лямбда должна быть hotel => hotel.HotelId, поскольку HotelId - это свойство Hotel, которое используется в качестве ключа документа.

Между прочим, ожидание внутри вашего блока catch не должно ждать постоянное количество времени. Если ваша поисковая служба сильно загружена, ожидание постоянной задержки не поможет дать ей время на восстановление. Вместо этого мы рекомендуем экспоненциальное отступление (например, первая задержка составляет 2 секунды, затем 4 секунды, затем 8 секунд, затем 16 секунд, вплоть до некоторого максимума).

person Bruce Johnston    schedule 13.10.2016
comment
Спасибо, Брюс. Я вижу, что это сработало. Я изменил свой код на этот: var retryBatch = e.FindFailedActionsToRetry ‹T› (batch, searchDoc = ›searchDoc.id); - person richard; 19.10.2016
comment
По иронии судьбы мой код экспоненциально откатывался, но для этого поста и простоты я изменил его на ровные 5 секунд. Я снова поменяю. Сколько повторных попыток с экспоненциальным увеличением вы бы порекомендовали? У меня сейчас 5. - person richard; 19.10.2016
comment
Вы можете продолжать повторять попытки до тех пор, пока вы добиваетесь прогресса (в пакете меньше элементов, чем при последнем вызове индекса), и ограничивать количество повторных попыток только тогда, когда вы не добиваетесь прогресса. В этом случае максимальное количество повторов должно зависеть от того, сколько времени вы готовы ждать, поскольку задержка экспоненциально увеличивается. После определенного момента вы можете переключиться с экспоненциальной задержки на постоянную (например, после того, как задержка достигнет нескольких минут, или все, что вы найдете, работает для вас). - person Bruce Johnston; 19.10.2016
comment
Каким-либо образом это можно проверить? Например, когда операция индексации завершается неудачно между 1000 записями, чтобы увидеть, не возникло ли исключение? - person Kevin Cohen; 17.08.2017
comment
@KevinCohen Вы пробовали издеваться над IDocumentsOperations.IndexWithHttpMessagesAsync? docs.microsoft.com/dotnet/api/ - person Bruce Johnston; 18.08.2017
comment
@BruceJohnston Привет, Брюс, не могли бы вы подробнее рассказать о своем комментарии? Я знаю, что эта функция существует, но как я могу использовать ее, чтобы принудительно выполнить индексацию? ставить случайные заголовки? - person Kevin Cohen; 18.08.2017
comment
@KevinCohen Какова ваша цель с точки зрения тестового покрытия? Вы пытаетесь задействовать написанный вами код для обработки исключения IndexBatchException и просто хотите его спровоцировать? Или вы пытаетесь провести настоящий сквозной тест типа обезьяны хаоса? - person Bruce Johnston; 18.08.2017
comment
Я хотел спровоцировать одного. Но мне помогли предположить, что я могу использовать слияние (без того, чтобы документ уже находился в лазурном поиске), поэтому это не удастся. Теперь я застрял в повторной попытке. Не могли бы вы взглянуть на это? stackoverflow.com/questions/45764070/ - person Kevin Cohen; 18.08.2017
comment
Рассмотрите возможность использования политики повторных попыток Polly для управления задержками повторных попыток и другими подобными факторами. - person bugged87; 17.03.2020
comment
В SDK есть механизмы для обработки повторных попыток, но они не применяются к ответам 207. В настоящее время мы работаем над новым .NET SDK, который должен обрабатывать больше таких частичных отказов, хотя это как минимум несколько месяцев. - person Bruce Johnston; 18.03.2020

Я принял рекомендации Брюса в его ответе и comment и реализовал его с помощью Полли.

  • Экспоненциальная задержка до одной минуты, после чего повторяется каждые две минуты.
  • Повторяйте, пока есть прогресс. Тайм-аут после 5 запросов без какого-либо прогресса.
  • IndexBatchException также выбрасывается для неизвестных документов. Я решил игнорировать такие непреходящие сбои, поскольку они, вероятно, указывают на запросы, которые больше не актуальны (например, удаленный документ в отдельном запросе).
int curActionCount = work.Actions.Count();
int noProgressCount = 0;

await Polly.Policy
    .Handle<IndexBatchException>() // One or more of the actions has failed.
    .WaitAndRetryForeverAsync(
        // Exponential backoff (2s, 4s, 8s, 16s, ...) and constant delay after 1 minute.
        retryAttempt => TimeSpan.FromSeconds( Math.Min( Math.Pow( 2, retryAttempt ), 60 ) ),
        (ex, _) =>
        {
            var batchEx = ex as IndexBatchException;
            work = batchEx.FindFailedActionsToRetry( work, d => d.Id );

            // Verify whether any progress was made.
            int remainingActionCount = work.Actions.Count();
            if ( remainingActionCount == curActionCount ) ++noProgressCount;
            curActionCount = remainingActionCount;
        } )
    .ExecuteAsync( async () =>
    {
        // Limit retries if no progress is made after multiple requests.
        if ( noProgressCount > 5 )
        {
            throw new TimeoutException( "Updating Azure search index timed out." );
        }

        // Only retry if the error is transient (determined by FindFailedActionsToRetry).
        // IndexBatchException is also thrown for unknown document IDs;
        // consider them outdated requests and ignore.
        if ( curActionCount > 0 )
        {
            await _search.Documents.IndexAsync( work );
        }
    } );
person Steven Jeuris    schedule 29.04.2020