Долгая работа надежной очереди Service Fabric

Я пытаюсь понять некоторые передовые практики для служебной ткани.

Если у меня есть очередь, которая добавляется веб-службой или каким-либо другим механизмом, и серверная задача для обработки этой очереди, что является лучшим подходом для обработки длительных операций в фоновом режиме.

  1. Используйте TryPeekAsync в одной транзакции, обработайте, а затем, в случае успеха, используйте TryDequeueAsync для окончательного удаления из очереди.
  2. Используйте TryDequeueAsync, чтобы удалить элемент, поместить его в словарь, а затем удалить из словаря по завершении. При запуске службы проверьте словарь на наличие чего-либо ожидающего перед очередью.

Оба способа кажутся немного неправильными, но я не могу понять, есть ли лучший способ.


person Nick Randell    schedule 01.03.2016    source источник


Ответы (2)


Один из вариантов - обработать очередь в RunAsync, что-то вроде этого:

protected override async Task RunAsync(CancellationToken cancellationToken)
{
    var store = await StateManager.GetOrAddAsync<IReliableQueue<T>>("MyStore").ConfigureAwait(false);
    while (!cancellationToken.IsCancellationRequested)
    {
        using (var tx = StateManager.CreateTransaction())
        {
            var itemFromQueue = await store.TryDequeueAsync(tx).ConfigureAwait(false);
            if (!itemFromQueue.HasValue)
            {
                await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken).ConfigureAwait(false);
                continue;
            }

            // Process item here
            // Remmber to clone the dequeued item if it is a custom type and you are going to mutate it.
            // If success, await tx.CommitAsync();
            // If failure to process, either let it run out of the Using transaction scope, or call tx.Abort();
        }
    }
}

Что касается комментария о клонировании элемента, удаленного из очереди, если вы хотите его изменить, просмотрите раздел «Рекомендации» здесь: https://azure.microsoft.com/en-us/documentation/articles/service-fabric-reliable-services-надежные-коллекции/

Одним из ограничений надежных коллекций (как очереди, так и словаря) является то, что у вас есть только 1 параллелизм на раздел. Так что для очередей с высокой активностью это может быть не лучшее решение. Возможно, это проблема, с которой вы столкнулись.

Мы использовали ReliableQueues для ситуаций, когда объем записи очень мал. Для очередей с более высокой пропускной способностью, где нам нужна надежность и масштабируемость, мы используем разделы ServiceBus. Это также дает нам то преимущество, что если служба была с отслеживанием состояния только из-за наличия ReliableQueue, теперь ее можно сделать без отслеживания состояния. Хотя это добавляет зависимость от сторонней службы (в данном случае ServiceBus), и это может не подойти вам.

Другой вариант - создать надежную реализацию pub / sub, которая будет действовать как очередь. Раньше я проводил тесты с использованием акторов для этого, и это показалось мне жизнеспособным вариантом, не тратя на это слишком много времени, поскольку у нас не было никаких проблем, связанных с ServiceBus. Вот еще одна SO об этом шаблоне Pub / sub в Azure Service Fabric

person anderso    schedule 01.03.2016
comment
Проблема, с которой я столкнулся, заключается в том, что транзакция остается открытой в течение некоторого времени, что не кажется правильным. Кроме того, если операция занимает более 4 секунд, транзакция в любом случае не выполняется. - person Nick Randell; 02.03.2016
comment
Сколько времени? Кроме того, как часто вы добавляете материалы в очередь? - person anderso; 02.03.2016
comment
Представьте, что какое-то время может составлять 1 минуту. Что касается сложения, то в часы пик может быть много раз в секунду. Я знаю, что если вы доведете это до крайности, вы можете просто сделать резервную копию работы. Я пытаюсь выяснить, существует ли лучший способ надежной обработки без возникновения тупиковой ситуации в системе. - person Nick Randell; 02.03.2016
comment
превосходно - это тоже согласуется с некоторыми из моих мыслей - мне нравится этот ответ - person Nick Randell; 02.03.2016
comment
@anderso - интересно, почему вы постоянно используете .ConfigureAwait(false) в ожидании асинхронной работы? - person Peter Lillevold; 10.02.2017
comment
@PeterLillevold См. stackoverflow.com/questions/13489065/ о том, зачем вызывать .ConfigureAwait(false) при вызовах ожидаемых асинхронных методов - person Stephanvs; 12.07.2017
comment
@Stephanvs действительно. И с большим количеством хороших дискуссий о том, почему не следует вызывать .ConfigureAwait(false). Отсюда мой вопрос, почему OP постоянно использует его в этом случае? Это потому, что есть некоторый прирост производительности, или это потому, что OP узнал, что это то, как вы должны это делать, не спрашивайте, почему ... - person Peter Lillevold; 12.07.2017

Если очень медленно, используйте 2 очереди. Одна быстрая, в которой вы храните работу без перерывов, а вторая медленная - для ее обработки. RunAsync используется для перемещения сообщений от быстрого к медленному.

person user1496062    schedule 07.08.2016