Версии оркестрации

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

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

Эта встроенная функция обеспечивает автоматическую изоляцию версий с минимальной конфигурацией. Это приложение, не зависящее от серверной архитектуры, поэтому любое приложение, использующее любого из поставщиков хранения Устойчивые функции, включая Durable Task Scheduler, может использовать данную технологию.

Пакеты SDK для устойчивых задач поддерживают два стиля управления версиями, которые можно использовать отдельно или вместе:

Терминология

В этой статье используются два связанных, но отдельных термина:

  • Функция Orchestrator (или просто "orchestrator"): код функции, определяющий логику рабочего процесса — шаблон или схему для выполнения рабочего процесса.
  • Экземпляр оркестрации (или просто оркестрация): конкретное выполнение функции оркестратора с собственным состоянием, идентификатором экземпляра и входными данными. Несколько экземпляров оркестрации могут выполняться одновременно из одной функции оркестратора.

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

Принцип работы

Управление версиями оркестрации основывается на этих основных принципах:

  • Связь версий: при создании экземпляра оркестрации она получает версию, которая постоянно связана с ней.
  • Выполнение с поддержкой версий: код Orchestrator проверяет значение версии, связанное с текущим экземпляром оркестрации, и разветвляет выполнение соответственно.
  • Обратная совместимость: рабочие, работающие под управлением более новых версий оркестратора, продолжают выполнять экземпляры оркестрации, созданные более старыми версиями.
  • Защита вперед. Среда выполнения запрещает рабочим, работающим с более старыми версиями оркестратора, выполнять оркестрации, запущенные более новыми версиями.

На практике вы устанавливаете строку версии по умолчанию на клиенте (или в host.json для Устойчивые функции), а код оркестратора использует context.Version для переключения между старой и новой логикой.

Необходимые условия

Прежде чем использовать управление версиями оркестрации, убедитесь, что у вас есть необходимые версии пакетов для языка программирования.

Если вы используете язык, отличный от .NET (JavaScript, Python, PowerShell или Java) с пакетами extension, приложение-функция должна ссылаться на Extension Bundle версии 4.30.0 или более поздней. Настройте диапазон extensionBundle в host.json, чтобы минимальная версия была по крайней мере 4.30.0. Рассмотрим пример.

{
    "version": "2.0",
    "extensionBundle": {
        "id": "Microsoft.Azure.Functions.ExtensionBundle",
        "version": "[4.30.0, 5.0.0)"
    }
}

Дополнительные сведения о выборе и обновлении версий пакета см. в документации по настройке пакета расширений.

Помимо требования пакета расширений для языков, отличных от .NET, также необходимо использовать минимальную версию пакета SDK для конкретного языка, указанного ниже. Для правильной работы управления версиями оркестрации необходимы как пакет расширений, так и пакет SDK.

Используйте Microsoft.Azure.Functions.Worker.Extensions.DurableTask версию 1.14.0 или более позднюю.

Установка версии по умолчанию

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

Добавьте или обновите параметр defaultVersion в файле host.json в проекте Функции Azure:

{
  "extensions": {
    "durableTask": {
      "defaultVersion": "<version>"
    }
  }
}

Строка версии может соответствовать любому формату, который соответствует стратегии управления версиями:

  • Многочастное версионирование: "1.0.0", "2.1.0"
  • Простое нумерирование: "1", "2"
  • На основе даты: "2025-01-01"
  • Пользовательский формат: "v1.0-release"

После установки defaultVersionвсе новые экземпляры оркестрации постоянно связаны с этой версией.

Задайте версию по умолчанию в построителе клиентов при настройке приложения.

Замечание

Доступно в пакете SDK .NET (Microsoft.DurableTask.Client.AzureManaged) с версии 1.9.0.

builder.Services.AddDurableTaskClient(builder =>
{
    builder.UseDurableTaskScheduler(connectionString);
    builder.UseDefaultVersion("1.0.0");
});

Версия является простой строкой и принимает любое значение. Пакет SDK пытается преобразовать его в System.Version, относящийся к .NET. В случае успешного выполнения эта библиотека используется для сравнения. В противном случае используется простое сравнение строк.

После установки версии по умолчанию на клиенте любая оркестрация, запущенная этим клиентом, постоянно связана с этой версией. Версия также доступна в контексте оркестрации, что даёт возможность использовать её в условных инструкциях.

Правила сравнения версий

При выборе стратегии Strict или CurrentOrOlder (см. Сопоставление версий), среда выполнения сравнивает версию экземпляра оркестрации со значением defaultVersion рабочей роли, используя следующие правила:

  • Пустые или нулевые версии рассматриваются как равные.
  • Пустая или нулевая версия считается более ранней, чем любая определенная версия.
  • Если обе версии являются числовыми (например, "1.0" и "2.0"), они сравниваются как номера версий, поэтому "2.0" новее, чем "1.0".
  • В противном случае выполняется сравнение строк без учета регистра.

В следующих примерах показано, как работает сравнение версий:

Версия A Версия B Результат
"1.0" "2.0" А старше
null "1.0" А старше
null null Равно
"v1-release" "v2-release" A старше (в алфавитном порядке)

Strict Если выбрана стратегия сопоставления версий CurrentOrOlder(см. сопоставление версий), сравнение версий зависит от языка:

  • .NET: SDK пытается распознать версию как System.Version. Если оба разбора завершатся успешно, выполняется сравнение CompareTo. В противном случае пакет SDK использует сравнение строк.
  • Python: пакет SDK использует packaging.version для сравнения семантических версий.
  • Java: SDK сравнивает версию как простую строку.

Логика оркестратора, учитывающая версии

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

Это важно

При реализации логики с поддержкой версий важно сохранить точную логику оркестратора для более старых версий. Любые изменения последовательности, порядка или подписи вызовов действий в существующих версиях могут нарушить детерминированное воспроизведение и вызвать сбои в текущих оркестрациях или привести к неправильным результатам. Сохраняйте прежние пути кода версии без изменений после развертывания.

[Function("MyOrchestrator")]
public static async Task<string> RunOrchestrator(
    [OrchestrationTrigger] TaskOrchestrationContext context)
{
    if (context.Version == "1.0")
    {
        // Original logic for version 1.0
        ...
    }
    else if (context.Version == "2.0")
    {
        // New logic for version 2.0
        ...
    }
    ...
}
[DurableTask]
class HelloCities : TaskOrchestrator<string, List<string>>
{
    private readonly string[] Cities = ["Seattle", "Amsterdam", "Hyderabad"];

    public override async Task<List<string>> RunAsync(
        TaskOrchestrationContext context, string input)
    {
        List<string> results = [];
        foreach (var city in Cities)
        {
            results.Add(await context.CallSayHelloAsync($"{city} v{context.Version}"));
            if (context.CompareVersionTo("2.0.0") >= 0)
            {
                results.Add(await context.CallSayGoodbyeAsync($"{city} v{context.Version}"));
            }
        }
        return results;
    }
}

Замечание

Свойство context.Version доступно только для чтения и отражает версию, которая постоянно связана с экземпляром оркестрации во время создания. Это значение нельзя изменить во время выполнения оркестрации.

Подсказка

Если вы уже создали оркестрации в процессе выполнения до указания версии по умолчанию, context.Version возвращает значение NULL (или эквивалент, зависящий от языка) для этих экземпляров. Структурируйте логику оркестратора, чтобы обрабатывать как устаревшие (без версии), так и новые версионированные оркестрации.

Поведение развертывания

Вот чего следует ожидать при развертывании обновленной функции оркестратора с новой логикой версии:

  • Сосуществование рабочих: рабочие, содержащие новый код функциональности оркестратора, запускаются, в то время как некоторые рабочие со старым кодом потенциально активны.
  • Назначение версий для новых экземпляров: всем новым оркестрациям и вложенным оркестрациям, созданным новыми работниками, назначается версия, полученная через defaultVersion.
  • Совместимость новых рабочих: новые работники могут обрабатывать как новые, так и ранее существующие оркестрации, поскольку логика ветвления, учитывающая версии, обеспечивает обратную совместимость.
  • Старые ограничения рабочей роли: старые работники могут обрабатывать только оркестрации с версией, равной или ниже версии, указанной в собственном defaultVersionhost.jsonкоде, так как они не должны иметь код оркестратора, совместимый с более новыми версиями.

Замечание

Версионирование оркестрации не влияет на жизненный цикл рабочих процессов. Платформа Функции Azure управляет настройкой рабочих процессов и снятием их с эксплуатации на основе стандартных правил в зависимости от моделей размещения.

Пример. Замена действия в последовательности

В этом примере показано, как заменить действие в середине последовательности с помощью оркестровки версий.

Версия 1.0

Конфигурация host.json:

{
  "extensions": {
    "durableTask": {
      "defaultVersion": "1.0"
    }
  }
}

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

[Function("ProcessOrderOrchestrator")]
public static async Task<string> ProcessOrder(
    [OrchestrationTrigger] TaskOrchestrationContext context)
{
    var orderId = context.GetInput<string>();

    await context.CallActivityAsync("ValidateOrder", orderId);
    await context.CallActivityAsync("ProcessPayment", orderId);
    await context.CallActivityAsync("ShipOrder", orderId);

    return "Order processed successfully";
}

Версия 2.0 с обработкой скидки

Конфигурация host.json:

{
  "extensions": {
    "durableTask": {
      "defaultVersion": "2.0"
    }
  }
}

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

[Function("ProcessOrderOrchestrator")]
public static async Task<string> ProcessOrder(
    [OrchestrationTrigger] TaskOrchestrationContext context)
{
    var orderId = context.GetInput<string>();

    await context.CallActivityAsync("ValidateOrder", orderId);

    if (TaskOrchestrationVersioningUtils.CompareVersions(context.Version, "1.0") <= 0)
    {
        // Preserve original logic for existing instances
        await context.CallActivityAsync("ProcessPayment", orderId);
    }
    else
    {
        // New logic with discount processing
        await context.CallActivityAsync("ApplyDiscount", orderId);
        await context.CallActivityAsync("ProcessPaymentWithDiscount", orderId);
    }

    await context.CallActivityAsync("ShipOrder", orderId);

    return "Order processed successfully";
}

Сопоставление версий

Стратегия сопоставления версий определяет, какие экземпляры оркестрации обрабатываются рабочими на основе совместимости версий.

В следующей таблице описаны доступные стратегии.

Стратегия Описание
Нет Версия не учитывается при обработке. Все работы обрабатываются независимо от версии.
Строгий Версия оркестрации и рабочая версия должны точно соответствовать.
CurrentOrOlder Версия оркестрации должна быть равна или меньше рабочей версии. Это стратегия по умолчанию.

Конфигурация

{
  "extensions": {
    "durableTask": {
      "defaultVersion": "<version>",
      "versionMatchStrategy": "CurrentOrOlder"
    }
  }
}
  • None (не рекомендуется): отключает проверку версий. Любой рабочий элемент обрабатывает любой экземпляр оркестрации.
  • Strict: обрабатывает задачи только из оркестрации с точно такой же версией, что и defaultVersion. Требует тщательной координации развертывания, чтобы избежать осиротевших оркестровок.
  • CurrentOrOlder (по умолчанию): обрабатывает задачи из оркестраций с версией, менее или равной defaultVersion. Обеспечивает обратную совместимость, предотвращая обработку новых оркестровок старыми сотрудниками.

Настройте стратегию сопоставления с помощью построителя рабочих ролей.

Замечание

Доступно в пакете SDK .NET (Microsoft.DurableTask.Worker.AzureManaged) с версии 1.9.0.

builder.Services.AddDurableTaskWorker(builder =>
{
    builder.AddTasks(r => r.AddAllGeneratedTasks());
    builder.UseDurableTaskScheduler(connectionString);
    builder.UseVersioning(new DurableTaskWorkerOptions.VersioningOptions
    {
        Version = "1.0.0",
        DefaultVersion = "1.0.0",
        MatchStrategy = DurableTaskWorkerOptions.VersionMatchStrategy.Strict,
        FailureStrategy = DurableTaskWorkerOptions.VersionFailureStrategy.Reject,
    });
});

Обработка несоответствия версий

Стратегия обработки несоответствия версий определяет, что происходит, если версия экземпляра оркестрации не соответствует рабочей версии.

В следующей таблице описаны доступные стратегии.

Стратегия Описание
Reject Оркестрация отклоняется и возвращается в рабочую очередь. Другой работник может попытаться позже. Эта стратегия используется по умолчанию.
Fail Оркестрация прошла с ошибкой и удаляется из очереди задач.

Конфигурация

{
  "extensions": {
    "durableTask": {
      "defaultVersion": "<version>",
      "versionFailureStrategy": "Reject"
    }
  }
}
  • Reject (по умолчанию): экземпляр оркестрации остается в текущем состоянии и может быть повторно запущен позже, когда совместимый рабочий процесс становится доступным. Эта стратегия является самым безопасным вариантом, так как она сохраняет состояние оркестрации.
  • Fail: немедленно завершает экземпляр оркестрации в состоянии ошибки. Этот параметр может быть подходящим, если несоответствия версий указывают на серьезные проблемы с развертыванием.

Когда следует использовать каждую стратегию

Отклонение: Используйте эту стратегию, когда необходимо повторить оркестровку позже или на другом рабочем узле. Reject Во время сбоя:

  1. Оркестрация отклоняется и возвращается в рабочую очередь.
  2. Другой работник отменяет оркестрацию.
  3. Оркестрация, извлеченная из очереди, может быть перенаправлена к другому работнику или вернуться к тому же самому.

Процесс повторяется до тех пор, пока не будет доступен работник, который сможет обрабатывать оркестрацию. Эта стратегия легко обрабатывает последовательное развертывание, в котором рабочие процессы обновляются постепенно.

Сбой: Используйте эту стратегию, при условии, что другой версии рабочего процесса невозможно обработать оркестровку. Оркестрация завершается ошибкой и переходит в завершающее состояние.

Замечание

Настройте стратегию обработки ошибок через свойство FailureStrategy в параметрах управления версиями, как показано в примерах кода сопоставления версий.

Запуск оркестровок с конкретными версиями

По умолчанию все новые экземпляры оркестровки используют текущий defaultVersion, указанный в host.json конфигурации. Однако у вас могут быть сценарии, в которых необходимо создать оркестрации с определенной версией, которая отличается от текущей версии по умолчанию.

Когда следует использовать определенные версии

  • Постепенная миграция. Продолжайте создавать оркестрации с более старой версией даже после развертывания более новой версии.
  • Сценарии тестирования: тестирование конкретной версии в рабочей среде.
  • Ситуации отката: временно вернуться к созданию экземпляров с предыдущей версией.
  • Рабочие процессы для конкретной версии: для различных бизнес-процессов требуются разные версии оркестрации.
[Function("HttpStart")]
public static async Task<HttpResponseData> HttpStart(
    [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post")] HttpRequestData req,
    [DurableClient] DurableTaskClient client,
    FunctionContext executionContext)
{
    var options = new StartOrchestrationOptions
    {
        Version = "1.0"
    };

    string instanceId = await client.ScheduleNewOrchestrationInstanceAsync(
        "ProcessOrderOrchestrator", orderId, options);
    // ...
}

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

[Function("MainOrchestrator")]
public static async Task<string> RunMainOrchestrator(
    [OrchestrationTrigger] TaskOrchestrationContext context)
{
    var subOptions = new SubOrchestratorOptions
    {
        Version = "1.0"
    };

    var result = await context.CallSubOrchestratorAsync<string>(
        "ProcessPaymentOrchestrator", orderId, subOptions);
    // ...
}

Удаление устаревших путей кода

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

Когда можно безопасно удалить устаревший код

  • Все экземпляры оркестрации с использованием старой версии завершены (успешны, провалены или остановлены).
  • Новые экземпляры оркестрации не будут созданы с старой версией.
  • Вы проверили с помощью мониторинга или запросов, что ни один экземпляр не работает с устаревшей версией.
  • Прошло достаточно времени с момента последнего развертывания старой версии.

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

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

Предупреждение

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

Лучшие практики

Управление версиями

  • Используйте многокомпонентное управление версиями: внедряйте согласованную схему управления версиями, например major.minor.patch.
  • Критические изменения в документе: четко документируйте, какие изменения требуют новой версии.
  • Управление жизненным циклом версии: определите время удаления устаревших участков кода.

Организация кода

  • Отдельная логика версий: используйте четкое разветвление или разделенные методы для разных версий.
  • Сохранение детерминизма: не изменяйте существующую логику версии после развертывания. Если изменения абсолютно необходимы, например критические исправления ошибок, убедитесь, что они поддерживают детерминированное поведение и не изменяют последовательность операций.
  • Тщательно протестируйте все пути версий, особенно во время переходов.

Мониторинг и наблюдаемость

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

Troubleshooting

Распространенные проблемы

  • Проблема: Экземпляры оркестрации, созданные с версией 1.0, вызывают сбой после развертывания версии 2.0

    • Решение. Убедитесь, что путь кода версии 1.0 в оркестраторе остается точно таким же. Любые изменения последовательности выполнения могут нарушить детерминированное воспроизведение.
  • Проблема. Рабочие, работающие под управлением более старых версий оркестратора, не могут запускать новые оркестрации

    • Решение. Это поведение ожидается. Среда выполнения предотвращает выполнение более старых рабочих процессов с более новыми версиями. Убедитесь, что все сотрудники обновлены до последней версии и что в их defaultVersion настройках host.json произведены соответствующие обновления.
  • Проблема: Сведения о версии недоступны в оркестраторе (context.Version или context.getVersion() - NULL, независимо от параметра defaultVersion)

    • Решение: Проверьте раздел Предварительные требования, чтобы убедиться, что ваша среда соответствует всем требованиям для версионирования оркестровки.
  • Проблема. Оркестрации более новой версии делают очень медленный ход или зависают

    • Решение. Эта проблема может иметь различные первопричины:
      1. Недостаточно новых рабочих ролей: убедитесь, что достаточно рабочих ролей, содержащих равную или более высокую версию, defaultVersion развертываются и активируются.
      2. Вмешательство более опытных работников в маршрутизацию оркестраций: более опытные работники могут вмешиваться в механизм маршрутизации оркестраций, усложняя получение оркестраций новыми работниками. Это вмешательство может быть особенно заметным для определенных поставщиков хранилища (служба хранилища Azure или MSSQL). Как правило, платформа Функции Azure гарантирует, что старые работники удаляются вскоре после развертывания, поэтому любая задержка обычно не является значительной. Рекомендуется использовать планировщик устойчивых задач для улучшенного механизма маршрутизации.

Troubleshooting

Распространенные проблемы

  • Проблема: Оркестрации зависают или не продвигаются после развертывания новой версии

    • Решение: Убедитесь, что MatchStrategy и FailureStrategy настроены правильно в опциях версионирования для рабочей роли. При использовании Strict сопоставления только рабочие с точно такой же версией могут обрабатывать эти оркестрации. Переключитесь на CurrentOrOlder, если вам нужна обратная совместимость.
  • Проблема: оркестрации сразу завершаются с ошибкой несоответствия версии

    • Решение. Проверьте, задано ли FailureStrategy значение Fail. Если это так, оркестрации, которые не соответствуют любой из доступных версий рабочих процессов, входят в состояние окончательной ошибки. Используйте Reject вместо этого, чтобы разрешить оркестрации оставаться в очереди до тех пор, пока не будет доступен совместимый рабочий элемент.
  • Проблема: возвращается context.VersionNone/null/undefined для экземпляров оркестрации

    • Решение. Оркестрации, созданные перед настройкой версии по умолчанию, не назначены версии. Убедитесь, что логика оркестратора обрабатывает значения версий в виде null или пустых строк как устаревший путь кода.

::: zone-end