Функция оркестровки Azure Durable срабатывает дважды

Я пытаюсь реализовать рабочий процесс долговечной функции Azure.

Каждые 6 минут у меня функция Azure TimerTrigger вызывает функцию оркестрации Azure (OrchestrationTrigger), которая, в свою очередь, запускает ряд функций активности (ActivityTrigger).

Однако иногда функция Orchestration вызывается дважды в течение нескольких секунд! Это большая проблема, поскольку мои функции активности не идемпотентны!

Ниже показано, как вызывается мой код.

Функция TimerTriggered:

[FunctionName("StartupFunc")]
public static async Task Run([TimerTrigger("0 */6 * * * *", RunOnStartup = true, UseMonitor = false)]TimerInfo myStartTimer, [OrchestrationClient] DurableOrchestrationClient orchestrationClient, TraceWriter log)
{
    List<OrchestrationModel> ExportModels = await getData();

    string id = await orchestrationClient.StartNewAsync("OrchestratorFunc", ExportModels);
}

Функция оркестровки:

[FunctionName("OrchestratorFunc")]
public static async Task<string> TransformOrchestration([OrchestrationTrigger] DurableOrchestrationContext context, TraceWriter log)
{
    var dataList = context.GetInput<List<OrchestrationModel>>();
    var tasks = new List<Task>();

    foreach (var data in dataList)
    {
        tasks.Add(context.CallActivityAsync<string>("TransformToSql", new TransformModel(data));
    }
    await Task.WhenAll(tasks);
}

Функция деятельности:

[FunctionName("TransformToSql")]
[public static async Task<string> RunTransformation([ActivityTrigger] DurableActivityContext context, TraceWriter log)
{
    TransformModel = context.GetInput<TransformModel>();

    //Do some work with TransformModel
}
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
4
0
4 381
2

Ответы 2

Такое поведение совершенно нормально - именно так работают долговечные функции.

У вас есть следующая оркестровка:

[FunctionName("OrchestratorFunc")]
public static async Task<string> TransformOrchestration([OrchestrationTrigger] DurableOrchestrationContext context, TraceWriter log)
{
    var dataList = context.GetInput<List<OrchestrationModel>>();
    var tasks = new List<Task>();

    foreach (var data in dataList)
    {
        tasks.Add(context.CallActivityAsync<string>("TransformToSql", new TransformModel(data));
    }
    await Task.WhenAll(tasks);
}

Когда вызывается действие, поток возвращается к концепции под названием Диспетчер - это внутреннее существо устойчивых функций, ответственное за поддержание потока вашей оркестровки. В ожидании завершения задачи оркестровка временно отключается. После выполнения задачи вся оркестровка воспроизводится до следующего await.

Важно то, что хотя оркестровка воспроизводится, действие не вызывается еще раз - его результат извлекается из хранилища и используется. Чтобы сделать вещи более явными, рассмотрим следующий пример:

[FunctionName("OrchestratorFunc")]
public static async Task<string> TransformOrchestration([OrchestrationTrigger] DurableOrchestrationContext context, TraceWriter log)
{
    var dataList = context.GetInput<List<OrchestrationModel>>();
    var tasks = new List<Task>();

    foreach (var data in dataList)
    {
        await context.CallActivityAsync<string>("TransformToSql1", new TransformModel(data);
        await context.CallActivityAsync<string>("TransformToSql2", new TransformModel(data);
    }
}

Когда ожидается TransformToSql1, оркестровка освобождается, и весь поток ожидает завершения этого действия. Затем оркестровка воспроизводится повторно - она ​​еще раз ожидает TransformToSql1, но, поскольку ее результат сохраняется, он просто возвращается к оркестровке и ожидает TransformToSql2 - затем процесс повторяется.

Я знаю о функциях воспроизведения действий, и это работает нормально, без каких-либо проблем. Моя проблема - это два одновременных выполнения функции Orchestrator.

Jeppe 13.09.2018 05:20

@ kamil-mrzyglod - так что, если моей функции оркестрации необходимо выполнить какой-то одноразовый код, который должен выполняться до того, как будут выполнены отдельные запросы активности, а не повторно запущены, что вы порекомендуете сделать? Выполнить это в отдельном отдельном действии, вызванном заранее?

Stephen Holt 06.06.2019 15:39

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

kamil-mrzyglod 06.06.2019 22:44

Функция оркестрации будет запускаться чаще, поскольку она воспроизводится платформой Durable Function. Вы видите, что ваши функции активности снова срабатывают? Если так, то это действительно странное поведение.

Устойчивые функции используют очереди хранения и таблицы для управления потоком и состоянием записи оркестровки.

Каждый раз, когда запускается функция оркестровки (получая сообщение из очереди управления), она воспроизводит оркестровку. Вы можете проверить это в коде, используя свойство IsReplaying на DurableOrchestrationContext.

if (!context.IsReplaying)
{
   // this code will only run during the first execution of the workflow
}

Не используйте IsReplaying для определения запуска действий, а используйте его для ведения журнала / отладки.

Когда функция действия достигнута, сообщение помещается в очередь рабочего элемента. Затем платформа Durable Functions изучит таблицу истории, чтобы определить, выполнялась ли эта функция активности ранее (с заданными параметрами). Если это так, то он не будет запускать функцию активности снова и продолжит выполнение остальной части функции оркестровки.

Функциональность контрольных точек и воспроизведения в Durable Functions работает только тогда, когда код оркестрации детерминирован. Поэтому никогда не используйте решения, основанные на DateTime или случайных числах.

Более подробная информация: https://docs.microsoft.com/en-us/azure/azure-functions/durable-functions-checkpointing-and-replay

Я вижу, что вторая функция оркестрации (пытается) выполняет точно такое же выполнение действий, что и первая функция оркестрации. Это приводит к множеству исключений и прерыванию работы.

Jeppe 13.09.2018 05:26

Другие вопросы по теме