it-swarm.com.ru

Как выполнить множество долговременных функций, запускаемых очередью Azure?

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

Функция, запускаемая очередью:

[FunctionName("MessageControllerExecutor")]
public static async void Run(
    [QueueTrigger(QUEUE_NAME, Connection = QUEUE_CONNECTION_NAME)]string queueMessage,
    [OrchestrationClient] DurableOrchestrationClient client,
    TraceWriter log)
{
    await client.StartNewAsync("MessageController", queueMessage);
}

Прочная функция:

[FunctionName("MessageController")]
public static async void Run(
    [OrchestrationTrigger] DurableOrchestrationContext context,
    TraceWriter log)
{
    if (!context.IsReplaying) log.Warning("MessageController started");

    var function1ResultTask = context.CallActivityAsync<ResultMessage>("Function_1", new InputMessage());
    var function2ResultTask = context.CallActivityAsync<ResultMessage>("Function_2", new InputMessage());

    await Task.WhenAll(function1ResultTask, function2ResultTask);

    // process Function_1 and Function_2 results
    // ...
}

Пример простой функции деятельности:

[FunctionName("Function_1")]
public static ResultMessage Run(
    [ActivityTrigger] DurableActivityContext activityContext,
    TraceWriter log)
{
    var msg = activityContext.GetInput<InputMessage>();
    int time = new Random().Next(1, 3);
    Thread.Sleep(time * 1000);

    return new ResultMessage()
    {
        Payload = $"Function_1 slept for {time} sec"
    };
}

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

Когда мы помещаем сообщения в очередь, функции MessageControllerExecutor запускаются немедленно и асинхронно, запускают MessageController и передают сообщение, чтобы оно работало, как ожидалось. Но мы столкнулись с проблемой того, что не все функции MessageController выполняются. Например, мы поместили 100 сообщений в очередь, но MessageController обработал только около 10-20% сообщений. Некоторые сообщения не были обработаны или были обработаны с большой задержкой. Похоже, что долговечные функции не удалось запустить, хотя никаких исключений не было.

Итак, у нас есть несколько вопросов:

  1. Правильно ли это решение с триггерными и долговременными функциями в очереди Для обработки очереди сообщений или есть лучший способ запуска долговременных функций из очереди? 
  2. Есть ли ограничения для запуска долговременных функций?
  3. Сколько долговременных функций может быть выполнено одновременно?
9
Taras Trofymchuk
  1. Да, это совершенно правильный способ начать оркестровку!
  2. Конечно, вот некоторые подробности об архитектуре в части, касающейся производительности и масштабируемости .
  3. Я думаю то, что вы, вероятно, намереваетесь спросить здесь: сколько экземпляров оркестрации одного определения длительной функции может быть выполнено одновременно? Это действительно очень важный аспект для понимания. Сами функции оркестровки являются однопоточными и, согласно той ссылке в масштабе, которую я дал вам выше, сбалансированы по набору контрольных очередей. Вы можете прочитать документ для получения дополнительной информации, но суть в том, что вы не хотите выполнять любой работу, отличную от фактической оркестровки в вашей функции оркестровки, поскольку они являются вашим ограничением масштабируемости. Это функции action оркестровки, которые ведут себя как любая другая функция Azure и практически не имеют ограничений по своей масштабируемости.

В целях краткости вы исключили какой-то код из своего триггера оркестровки в приведенном выше вопросе, но я понимаю, что именно вы там делаете после await Task.WhenAll(...)? Если он включает в себя какой-либо значительный процесс обработки, вы действительно должны обработать его для выполнения третьей функции действия (например, Function_3), а затем просто вернуть результаты из функции оркестровки.

Update: Я только что заметил, что ваши функции определены как async void. Если бы мне пришлось угадывать, это на самом деле вызовет проблемы во время выполнения. Можете ли вы попробовать изменить его на async Task и посмотреть, исчезнет ли ваша проблема? Как общее правило определение методов как async void осуждается в .NET .

5
Drew Marsh

Некоторое расширение для ответа Дрю. Вы не должны использовать Thread.Sleep (), поскольку в документации состояния , вместо этого используйте CreateTimer Api.

1
SayusiAndo