Ограничения кода функции оркестратора

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

Ограничения кода оркестратора

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

Использование детерминированных API

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

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

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

Примечание

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

Даты и время

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

Не используйте DateTime.Now, DateTime.UtcNow или эквивалентные им API для получения текущего времени. Кроме того, следует избегать таких классов, как Stopwatch. Для внутрипроцессных функций оркестратора .NET для получения текущего времени используйте свойство IDurableOrchestrationContext.CurrentUtcDateTime. Для изолированных функций оркестратора .NET для получения текущего времени используйте свойство TaskOrchestrationContext.CurrentDateTimeUtc.

DateTime startTime = context.CurrentUtcDateTime;
// do some work
TimeSpan totalTime = context.CurrentUtcDateTime.Subtract(startTime);

Идентификаторы GUID и UUID

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

Не используйте для генерирования случайным образом идентификаторов GUID интерфейсы API, например Guid.NewGuid(). Вместо этого используйте API объекта контекста NewGuid(), чтобы сгенерировать случайным образом GUID, который не приведет к сбою при многократном воспроизведении оркестратора.

Guid randomGuid = context.NewGuid();

Примечание

Идентификаторы GUID, созданные с помощью API контекста оркестрации, являются идентификаторами UUID типа 5.

Случайные числа

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

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

Привязки

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

Статические переменные

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

Примечание

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

Переменные среды

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

Сеть и HTTP

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

API для блокировки потоков

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

Асинхронные API

Код оркестратора никогда не должен запускать асинхронную операцию, за исключением тех, которые определены контекстным объектом триггера оркестрации. Например, не используйте Task.Run, Task.Delay и HttpClient.SendAsync в .NET или setTimeout и setInterval в JavaScript. Функция оркестратора должна планировать асинхронную работу только с помощью API устойчивых пакетов SDK, таких как функции планирования действий. Любые другие асинхронные вызовы должны выполняться внутри функций действий.

Асинхронные функции JavaScript

Функции оркестратора JavaScript следует всегда объявлять как синхронные функции генератора. Нельзя объявлять функции оркестратора JavaScript как async, так как среда выполнения node.js не гарантирует детерминированность асинхронных функций.

Сопрограммы Python

Вы не должны объявлять функции оркестратора Python как сопрограммы. Иными словами не стоит объявлять функции оркестратора Python с помощью ключевого слова async, так как семантика сопрограммы не согласуется с моделью воспроизведения Устойчивых функций. Необходимо всегда объявлять функции оркестратора Python как генераторы, то есть следует ожидать, что API context будет использовать yield, а не await.

API для работы с потоками .NET

Платформа устойчивых задач запускает код оркестратора в одном потоке и не может взаимодействовать с другими потоками. Асинхронное продолжение оркестрации в потоке рабочего пула может привести к недетерминированному выполнению или взаимоблокировкам. Поэтому функции оркестратора практически никогда не должны использовать API работы с потоками. Например, никогда не используйте ConfigureAwait(continueOnCapturedContext: false) в функции оркестратора. Это гарантирует продолжение выполнения задач в исходной SynchronizationContext функции оркестратора.

Примечание

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

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

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

Устойчивые задачи

Примечание

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

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

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

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

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

Чтобы узнать больше о том, как платформа устойчивых задач выполняет функции оркестратора, см. статью Исходный код устойчивой задачи на сайте GitHub. В частности, просмотрите сведения о TaskOrchestrationExecutor.cs и TaskOrchestrationContext.cs.

Дальнейшие действия