Устойчивые оркестрации

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

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

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

Идентификатор оркестрации

Каждый экземпляр оркестрации обладает идентификатором экземпляра (также известный как ИД экземпляра). По умолчанию каждый идентификатор экземпляра является автоматически созданным глобальным уникальным идентификатором (GUID). Однако идентификаторы экземпляров также могут быть любыми строковыми значениями, созданными пользователем. Идентификатор каждого экземпляра оркестрации должен быть уникальным в пределах центра задач.

Ниже приведены некоторые правила для идентификаторов экземпляров.

  • Идентификаторы экземпляров должны быть от 1 до 100 символов.
  • Идентификаторы экземпляров не должны начинаться со знака @.
  • Идентификаторы экземпляров не должны содержать символы /, \, # или ?.
  • Идентификаторы экземпляров не должны содержать управляющие символы.

Примечание.

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

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

Идентификатор экземпляра оркестрации является обязательным параметром для большинства операций управления экземпляром. Они также важны для диагностики, например для поиска в данных отслеживания оркестрации в Application Insights для устранения неполадок или аналитики. По этой причине рекомендуется сохранять созданные идентификаторы экземпляров за пределами текущей среды (например, в базе данных или в журналах приложений), где на них можно будет легко ссылаться позже.

Надежность

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

Устойчивые функции прозрачно используют источник событий. По сути оператор await (C#) или yield (JavaScript или Python) в функции оркестратора передает управление потоком оркестратора обратно диспетчеру платформы устойчивых задач. В случае Java специальное ключевое слово языка отсутствует. Вместо этого вызов .await() задачи возвращает управление диспетчеру с помощью пользовательского Throwable. Затем диспетчер совершает любые новые действия, запланированные функцией оркестратора (например, вызов одной или нескольких дочерних функций или планирование устойчивого таймера) в хранилище. Действие прозрачной фиксации обновляет историю выполнений экземпляра оркестрации путем добавления всех новых событий в хранилище как в журнале "только для добавления". Аналогичным образом действие фиксации создает в хранилище сообщения с целью планирования фактической работы. На этом этапе функцию оркестрации можно выгрузить из памяти. По умолчанию в качестве хранилища состояний среды выполнения устойчивые функции используют службу хранилища Azure, но поддерживаются и другие поставщики хранилищ.

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

Примечание.

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

Примечание.

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

Журнал оркестраций

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

Примечание.

Общедоступна версия 4 модели программирования Node.js для Функции Azure. Новая модель версии 4 предназначена для более гибкого и интуитивно понятного интерфейса для разработчиков JavaScript и TypeScript. Дополнительные сведения о различиях между версиями 3 и 4 см. в руководстве по миграции.

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

[FunctionName("HelloCities")]
public static async Task<List<string>> Run(
    [OrchestrationTrigger] IDurableOrchestrationContext context)
{
    var outputs = new List<string>();

    outputs.Add(await context.CallActivityAsync<string>("SayHello", "Tokyo"));
    outputs.Add(await context.CallActivityAsync<string>("SayHello", "Seattle"));
    outputs.Add(await context.CallActivityAsync<string>("SayHello", "London"));

    // returns ["Hello Tokyo!", "Hello Seattle!", "Hello London!"]
    return outputs;
}

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

Таблица журнала

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

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

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

Примечание.

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

По завершении приведенный выше журнал функций будет выглядеть примерно как в следующей таблице в хранилище таблиц Azure (следующий пример приведен в сокращенном виде):

PartitionKey (InstanceId) EventType Метка времени Входные данные имени Результат Состояние
eaee885b ExecutionStarted 2021-05-05T18:45:28.852Z null HelloCities
eaee885b OrchestratorStarted 2021-05-05T18:45:32.362Z
eaee885b TaskScheduled 2021-05-05T18:45:32.670Z SayHello
eaee885b OrchestratorCompleted 2021-05-05T18:45:32.670Z
eaee885b TaskCompleted 2021-05-05T18:45:34.201Z """Hello Tokyo!"""
eaee885b OrchestratorStarted 2021-05-05T18:45:34.232Z
eaee885b TaskScheduled 2021-05-05T18:45:34.435Z SayHello
eaee885b OrchestratorCompleted 2021-05-05T18:45:34.435Z
eaee885b TaskCompleted 2021-05-05T18:45:34.763Z """Hello Seattle!"""
eaee885b OrchestratorStarted 2021-05-05T18:45:34.857Z
eaee885b TaskScheduled 2021-05-05T18:45:34.857Z SayHello
eaee885b OrchestratorCompleted 2021-05-05T18:45:34.857Z
eaee885b TaskCompleted 2021-05-05T18:45:34.919Z """Hello London!"""
eaee885b OrchestratorStarted 2021-05-05T18:45:35.032Z
eaee885b OrchestratorCompleted 2021-05-05T18:45:35.044Z
eaee885b ExecutionCompleted 2021-05-05T18:45:35.044Z "[""Hello Tokyo!"",""Hello Seattle!"",""Hello London!""]" Завершено

Некоторые сведения о значениях столбцов:

  • PartitionKey. Содержит идентификатор экземпляра оркестрации.
  • EventType. Предоставляет тип события. Подробные описания всех типов событий журнала можно найти здесь.
  • Timestamp. Метка времени события журнала в формате UTC.
  • Name. Имя вызванной функции.
  • Input. Входные данные функции в формате JSON.
  • Result. Выходные данные функции (то есть ее возвращаемое значение).

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

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

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

Возможности и шаблоны

В следующих разделах описываются функции и шаблоны функций оркестратора.

Вложенные оркестрации

Функции оркестратора могут вызывать функции действия, а также другие функции оркестратора. Например, вы можете построить создать крупную оркестрацию из библиотеки функций оркестратора. Или можно запустить несколько экземпляров функции оркестратора одновременно.

Дополнительные сведения и примеры см. в статье Sub-orchestrations in Durable Functions (Azure Functions) (Вложенные оркестрации в устойчивых функциях (Функции Azure)).

Устойчивые таймеры

Оркестрации могут планировать устойчивые таймеры для реализации задержек или для настройки обработки времени ожидания при асинхронных действиях. Используйте устойчивые таймеры в функциях оркестратора вместо API спящего режима для используемого языка.

Дополнительные сведения и примеры см. в статье Timers in Durable Functions (Azure Functions) (Таймеры в устойчивых функциях (Функции Azure)).

Внешние события

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

Дополнительные сведения и примеры см. в статье Handling external events in Durable Functions (Azure Functions) (Обработка внешних событий в устойчивых функциях (Функции Azure)).

Обработка ошибок

Функции оркестратора могут использовать функции обработки ошибок языка программирования. Существующие шаблоны, такие как try/catch, поддерживаются в коде оркестрации.

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

Примечание.

Если в функции оркестратора есть необработанное исключение, экземпляр оркестрации завершится в состоянии Failed. Экземпляр оркестрации нельзя повторить после сбоя.

Дополнительные сведения и примеры см. в статье Handling errors in Durable Functions (Azure Functions) (Обработка ошибок в устойчивых функциях (Функции Azure)).

Критические разделы (Устойчивые функции 2.x сейчас поддерживается только .NET)

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

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

[FunctionName("Synchronize")]
public static async Task Synchronize(
    [OrchestrationTrigger] IDurableOrchestrationContext context)
{
    var lockId = new EntityId("LockEntity", "MyLockIdentifier");
    using (await context.LockAsync(lockId))
    {
        // critical section - only one orchestration can enter at a time
    }
}

Объект LockAsync приобретает устойчивые замки и возвращает объект IDisposable, который завершает критическую секцию при удалении. Этот результат IDisposable можно использовать вместе с блоком using, чтобы получить синтаксическое представление критической секции. Когда функция оркестратора входит в критическую секцию, только один экземпляр может выполнить этот блок кода. Любые другие экземпляры, которые пытаются войти в критическую секцию, будут заблокированы, пока предыдущий экземпляр не выйдет из критической секции.

Функция критической секции также полезна для согласования изменений в устойчивых сущностях. Дополнительные сведения о критических секциях см. в статье Entity functions (preview) (Функции сущностей (предварительная версия)).

Примечание.

Критические разделы доступны в Устойчивые функции 2.0. В настоящее время только оркестрации .NET в proc реализуют эту функцию. Сущности и критические разделы пока недоступны в Устойчивые функции для рабочей роли, изолированной от dotnet.

Вызов конечных точек HTTP (Устойчивые функции 2.x)

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

Чтобы упростить этот распространенный шаблон, функции оркестратора могут использовать метод CallHttpAsync для вызова API-интерфейсов HTTP напрямую.

[FunctionName("CheckSiteAvailable")]
public static async Task CheckSiteAvailable(
    [OrchestrationTrigger] IDurableOrchestrationContext context)
{
    Uri url = context.GetInput<Uri>();

    // Makes an HTTP GET request to the specified endpoint
    DurableHttpResponse response = 
        await context.CallHttpAsync(HttpMethod.Get, url);

    if ((int)response.StatusCode == 400)
    {
        // handling of error codes goes here
    }
}

Помимо поддержки базовых шаблонов запросов/ответов, метод поддерживает автоматическую обработку общих асинхронных шаблонов опроса HTTP 202, а также проверку подлинности с помощью внешних служб с использованием Управляемых удостоверений.

Дополнительные сведения и подробные примеры см. в статье HTTP Features (Функции HTTP).

Примечание.

Вызов конечных точек HTTP напрямую из функций оркестратора доступен в Устойчивых функциях версии 2.0 и выше.

Передача нескольких параметров

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

В .NET также можно использовать объекты ValueTuple. В следующем примере используются новые функции ValueTuple, добавленные в C# 7:

[FunctionName("GetCourseRecommendations")]
public static async Task<object> RunOrchestrator(
    [OrchestrationTrigger] IDurableOrchestrationContext context)
{
    string major = "ComputerScience";
    int universityYear = context.GetInput<int>();

    object courseRecommendations = await context.CallActivityAsync<object>(
        "CourseRecommendations",
        (major, universityYear));
    return courseRecommendations;
}

[FunctionName("CourseRecommendations")]
public static async Task<object> Mapper([ActivityTrigger] IDurableActivityContext inputs)
{
    // parse input for student's major and year in university
    (string Major, int UniversityYear) studentInfo = inputs.GetInput<(string, int)>();

    // retrieve and return course recommendations by major and university year
    return new
    {
        major = studentInfo.Major,
        universityYear = studentInfo.UniversityYear,
        recommendedCourses = new []
        {
            "Introduction to .NET Programming",
            "Introduction to Linux",
            "Becoming an Entrepreneur"
        }
    };
}

Следующие шаги