Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Important
Поддержка будет завершена для внутрипроцессной модели 10 ноября 2026 г. Мы настоятельно рекомендуем перенести ваши приложения на изолированную модель рабочих процессов для полной поддержки.
Расширение устойчивых функций предоставляет триггеры и выходные привязки, которые подключают код к среде выполнения Устойчивых функций для оркестрации рабочих процессов. Используйте эти привязки для определения функций оркестратора, функций действий, функций сущностей и клиентских функций, которые запускают устойчивые рабочие процессы и управляют ими.
В этой статье объясняется, как настроить и использовать каждую привязку (триггер оркестрации, триггер действия, триггер сущности и клиент оркестрации) с примерами кода для каждого поддерживаемого языка.
Выберите язык разработки устойчивых функций в верхней части статьи.
Устойчивые функции поддерживают обе версии модели программирования Python для функций Azure. Так как Python v2 является рекомендуемой, примеры в этой статье представлены исключительно в этой версии.
Необходимые условия
- пакет SDK Устойчивые функции, который является пакетом Индекса пакетов Python (PyPI)
azure-functions-durable, версии1.2.2или более поздней - Пакет расширений версии 4.x (или более поздняя версия), который устанавливается в файле проекта host.json
Вы можете предоставить отзывы и предложения в пакете SDK Устойчивые функции для репозитория Python.
Триггер оркестрации
Триггер оркестрации можно использовать для разработки устойчивых функций оркестратора. Этот триггер выполняется в момент, когда планируется новый экземпляр оркестрации, и в момент, когда существующий экземпляр оркестрации получает событие. Примеры событий, которые могут активировать функции оркестратора, включают истечения срока действия долговечного таймера, ответы функций активности и события, вызываемые внешними клиентами.
При разработке функций в .NET используйте атрибут OrchestrationTriggerAttribute .NET для настройки триггера оркестрации.
Для Java вы используете аннотацию @DurableOrchestrationTrigger для настройки триггера оркестрации.
При использовании версии 4 модели программирования Node.js для разработки функций вы импортируете app объект из @azure/functions npm модуля. Затем вы вызываете app.orchestration метод API устойчивых функций непосредственно в коде функции. Этот метод регистрирует функцию оркестратора с помощью платформы Устойчивые функции.
При записи функций оркестратора необходимо определить триггер оркестрации с помощью следующего объекта JSON в массиве bindings файла function.json :
{
"name": "<name-of-input-parameter-in-function-signature>",
"orchestration": "<optional-name-of-orchestration>",
"type": "orchestrationTrigger",
"direction": "in"
}
Значением orchestration является имя оркестрации, которую клиенты должны использовать при запуске новых экземпляров функции оркестратора. Это свойство является необязательным. Если он не указан, используется имя функции.
При использовании модели программирования Python версии 2 можно определить триггер оркестрации с помощью декоратора orchestration_trigger непосредственно в коде функции Python.
В модели версии 2 вы получаете доступ к триггерам и привязкам в рамках Устойчивые функции из экземпляра DFApp. Этот подкласс FunctionApp можно использовать для экспорта декораторов, специфических для Устойчивые функции.
Внутри этого триггера привязка проверяет настроенное долгосрочное хранилище на наличие новых событий управления оркестрацией. Примеры событий:
- События запуска оркестрации
- События окончания срока действия долговечных таймеров
- События отклика функции активности
- Внешние события, вызванные другими функциями
Поведение триггера оркестрации
Ниже приведены некоторые заметки о триггере оркестрации:
- Однопоточность: Один диспетчерский поток используется для выполнения всех функций оркестратора в одном узле. По этой причине важно убедиться, что код функции оркестратора эффективен и не выполняет никаких операций ввода-вывода. Кроме того, важно убедиться, что этот поток не выполняет асинхронную работу, за исключением случаев ожидания типов задач, относящихся к устойчивым функциям.
- Обработка ядовитых сообщений: в триггерах оркестрации нет поддержки ядовитых сообщений.
- Видимость сообщений: оркестрационные триггерные сообщения извлекаются из очереди и остаются невидимыми в течение настраиваемой длительности. Видимость этих сообщений обновляется автоматически, пока приложение-функция работает исправно.
- Возвращаемые значения: возвращаемые значения сериализуются в JSON и сохраняются в таблице журнала оркестрации в хранилище таблиц Azure. Эти возвращаемые значения можно запросить с помощью привязки клиента оркестрации, описанной далее.
Предупреждение
Функции оркестратора никогда не должны использовать входные или выходные привязки, отличные от привязки триггера оркестрации. Использование других привязок может вызвать проблемы с расширением Durable Task, так как эти привязки могут не подчиняться правилам однопоточности и ввода-вывода. Если вы хотите использовать другие привязки, добавьте их в функцию действия, вызванную из функции оркестратора. Дополнительные сведения о ограничениях кода для функций оркестратора см. в разделе "Ограничения кода функции Orchestrator".
Предупреждение
Функции оркестратора никогда не должны объявляться async.
Использование триггера оркестрации
Привязка (биндинг) триггера оркестрации поддерживает входные и выходные данные. Ниже приведены некоторые заметки о обработке входных и выходных данных:
- Входные данные: можно вызвать триггеры оркестрации, имеющие входные данные. Входные данные доступны через объект входных данных контекста. Все входные данные должны быть сериализуемыми в формате JSON.
- Выходные данные: триггеры оркестрации поддерживают как входные, так и выходные значения. Возвращаемое значение функции используется для назначения выходного значения. Возвращаемое значение должно быть сериализуемым в формате JSON.
Образец триггера оркестрации
В следующем коде представлен пример базовой функции оркестратора Hello World. В этом примере оркестратор не планирует никаких задач.
Атрибут, используемый для определения триггера, зависит от того, выполняются ли функции C#:
[FunctionName("HelloWorld")]
public static string RunOrchestrator([OrchestrationTrigger] IDurableOrchestrationContext context)
{
string name = context.GetInput<string>();
return $"Hello {name}!";
}
Note
Предыдущий код предназначен для Устойчивые функции 2.x. Для Устойчивые функции 1.x необходимо использовать DurableOrchestrationContext вместо IDurableOrchestrationContext. Дополнительные сведения о различиях между версиями см. в обзоре версий Устойчивые функции.
const { app } = require('@azure/functions');
const df = require('durable-functions');
df.app.orchestration('helloOrchestrator', function* (context) {
const name = context.df.getInput();
return `Hello ${name}`;
});
Note
Библиотека durable-functions вызывает синхронный context.done метод при выходе функции генератора.
import azure.functions as func
import azure.durable_functions as df
myApp = df.DFApp(http_auth_level=func.AuthLevel.ANONYMOUS)
@myApp.orchestration_trigger(context_name="context")
def my_orchestrator(context):
result = yield context.call_activity("Hello", "Tokyo")
return result
param($Context)
$InputData = $Context.Input
$InputData
@FunctionName("HelloWorldOrchestration")
public String helloWorldOrchestration(
@DurableOrchestrationTrigger(name = "ctx") TaskOrchestrationContext ctx) {
return String.format("Hello %s!", ctx.getInput(String.class));
}
Большинство функций оркестратора вызывают функции действия. Следующий код содержит пример Hello World, демонстрирующий вызов функции действия:
[FunctionName("HelloWorld")]
public static async Task<string> RunOrchestrator(
[OrchestrationTrigger] IDurableOrchestrationContext context)
{
string name = context.GetInput<string>();
string result = await context.CallActivityAsync<string>("SayHello", name);
return result;
}
Note
Предыдущий код предназначен для Устойчивые функции 2.x. Для Устойчивые функции 1.x необходимо использовать DurableOrchestrationContext вместо IDurableOrchestrationContext. Дополнительные сведения о различиях между версиями см. в обзоре версий Устойчивые функции.
const { app } = require('@azure/functions');
const df = require('durable-functions');
const activityName = 'hello';
df.app.orchestration('helloOrchestrator', function* (context) {
const name = context.df.getInput();
const result = yield context.df.callActivity(activityName, name);
return result;
});
@FunctionName("HelloWorld")
public String helloWorldOrchestration(
@DurableOrchestrationTrigger(name = "ctx") TaskOrchestrationContext ctx) {
String input = ctx.getInput(String.class);
String result = ctx.callActivity("SayHello", input, String.class).await();
return result;
}
Триггер действия
Триггер действия можно использовать для разработки функций, называемых функциями действий , которые вызываются функциями оркестратора.
Для настройки триггера действия используется атрибут ActivityTriggerAttribute .NET.
С помощью заметки @DurableActivityTrigger можно настроить триггер действия.
Чтобы зарегистрировать функцию действия, импортируйте app объект из @azure/functions npm модуля. Затем вы вызываете app.activity метод API устойчивых функций непосредственно в коде функции.
Чтобы определить триггер действия, используйте следующий объект JSON в массиве bindingsfunction.json:
{
"name": "<name-of-input-parameter-in-function-signature>",
"activity": "<optional-name-of-activity>",
"type": "activityTrigger",
"direction": "in"
}
Значением activity является имя действия. Это значение — имя, используемое функциями оркестратора для вызова этой функции действия. Это свойство является необязательным. Если он не указан, используется имя функции.
Триггер действия можно определить с помощью декоратора activity_trigger непосредственно в коде функции Python.
В этой триггерной привязке система опрашивает настроенное устойчивое хранилище на предмет новых событий выполнения активности.
Поведение триггера
Ниже приведены некоторые заметки о триггере действия:
- Потоки. В отличие от триггера оркестрации, триггеры действий не имеют ограничений на потоки или операции ввода-вывода. Их можно рассматривать как обычные функции.
- Обработка подозрительных сообщений: в триггерах активности нет поддержки подозрительных сообщений.
- Видимость сообщения: сообщения триггеров активности извлекаются из очереди и сохраняются невидимыми в течение настраиваемой продолжительности. Видимость этих сообщений обновляется автоматически, пока приложение-функция работает исправно.
- Возвращаемые значения: возвращаемые значения сериализуются в JSON и сохраняются в настроенном устойчивом хранилище.
Использование триггера
Привязка триггера действия поддерживает как входные данные, так и выходные, как и триггер оркестрации. Ниже приведены некоторые заметки о обработке входных и выходных данных:
- Входные данные: триггеры действий можно вызывать с помощью входных данных из функции оркестратора. Все входные данные должны быть сериализуемыми в формате JSON.
- Выходные данные: функции действий поддерживают как выходные, так и входные значения. Возвращаемое значение функции используется для назначения выходного значения и должно быть сериализуемым в формате JSON.
-
Metadata: функции действия .NET могут привязаться к параметру
string instanceId, чтобы получить идентификатор экземпляра вызывающей оркестрации.
Пример триггера
В следующем коде представлен пример базовой функции действия Hello World.
[FunctionName("SayHello")]
public static string SayHello([ActivityTrigger] IDurableActivityContext helloContext)
{
string name = helloContext.GetInput<string>();
return $"Hello {name}!";
}
Тип параметра по умолчанию для привязки .NET ActivityTriggerAttribute — IDurableActivityContext (или DurableActivityContext для Устойчивые функции 1.x). Однако триггеры действий .NET также поддерживают привязку непосредственно к сериализуемым типам JSON (включая примитивные типы), поэтому можно также использовать следующую упрощенную версию функции:
[FunctionName("SayHello")]
public static string SayHello([ActivityTrigger] string name)
{
return $"Hello {name}!";
}
const { app } = require('@azure/functions');
const df = require('durable-functions');
const activityName = 'hello';
df.app.activity(activityName, {
handler: (input) => {
return `Hello, ${input}`;
},
});
import azure.functions as func
import azure.durable_functions as df
myApp = df.DFApp(http_auth_level=func.AuthLevel.ANONYMOUS)
@myApp.activity_trigger(input_name="myInput")
def my_activity(myInput: str):
return "Hello " + myInput
param($name)
"Hello $name!"
@FunctionName("SayHello")
public String sayHello(@DurableActivityTrigger(name = "name") String name) {
return String.format("Hello %s!", name);
}
Использование привязок входных и выходных данных активности
Помимо привязки триггера действия можно также использовать обычные входные и выходные привязки.
Например, функция действия может получать входные данные из функции оркестратора. Затем функция действия может отправлять эти входные данные в виде сообщения в Центры событий Azure.
const { app } = require('@azure/functions');
const df = require('durable-functions');
df.app.orchestration('helloOrchestrator', function* (context) {
const input = context.df.getInput();
yield context.df.callActivity('sendToEventHub', input);
return `Message sent: ${input}`;
});
const { EventHubProducerClient } = require("@azure/event-hubs");
const connectionString = process.env.EVENT_HUB_CONNECTION_STRING;
const eventHubName = process.env.EVENT_HUB_NAME;
df.app.activity("sendToEventHub", {
handler: async (message, context) => {
const producer = new EventHubProducerClient(connectionString, eventHubName);
try {
const batch = await producer.createBatch();
batch.tryAdd({ body: message });
await producer.sendBatch(batch);
context.log(`Message sent to Event Hubs: ${message}`);
} catch (err) {
context.log.error("Failed to send message to Event Hubs:", err);
throw err;
} finally {
await producer.close();
}
},
});
app.storageQueue('helloQueueStart', {
queueName: 'start-orchestration',
extraInputs: [df.input.durableClient()],
handler: async (message, context) => {
const client = df.getClient(context);
const orchestratorName = message.orchestratorName || 'helloOrchestrator';
const input = message.input || null;
const instanceId = await client.startNew(orchestratorName, { input });
context.log(`Started orchestration with ID = '${instanceId}'`);
},
});
Клиент для оркестрации систем
Вы можете использовать привязку клиента оркестрации для записи функций, взаимодействующих с функциями оркестратора. Эти функции часто называются клиентскими функциями. Например, вы можете выполнять действия с экземплярами оркестрации следующими методами:
- Запустите их.
- Запросить их статус.
- Устраните их.
- Отправка событий им, пока они выполняются.
- Очистить историю экземпляров.
Вы можете привязаться к клиенту оркестрации с помощью атрибута DurableClientAttribute (OrchestrationClientAttribute в Устойчивые функции 1.x).
Вы можете привязаться к клиенту оркестрации с помощью аннотации @DurableClientInput.
Чтобы зарегистрировать клиентную функцию, импортируйте app объект из @azure/functions npm модуля. Затем вы вызываете метод API устойчивых функций, который зависит от типа триггера. Например, для триггера HTTP вызывается app.http метод. Для триггера очереди вызывается app.storageQueue метод.
Чтобы определить устойчивый триггер клиента, используйте следующий объект JSON в массиве bindingsfunction.json:
{
"name": "<name-of-input-parameter-in-function-signature>",
"taskHub": "<optional-name-of-task-hub>",
"connectionName": "<optional-name-of-connection-string-app-setting>",
"type": "orchestrationClient",
"direction": "in"
}
- Это
taskHubсвойство используется, если несколько приложений-функций используют одну и ту же учетную запись хранения, но их необходимо изолировать друг от друга. Если это свойство не указано, используется значение по умолчанию из host.json . Это значение должно соответствовать значению, используемому целевыми функциями оркестратора. - Значение
connectionName— это имя параметра приложения, содержащего строку подключения учетной записи хранения. Учетная запись хранения, представленная этой строкой подключения, должна совпадать с той, которую используют целевые функции оркестратора. Если это свойство не указано, используется строка подключения учетной записи хранения по умолчанию для функционального приложения.
Note
В большинстве случаев рекомендуется опустить эти свойства и полагаться на поведение по умолчанию.
Вы можете определить устойчивый триггер клиента с помощью декоратора durable_client_input непосредственно в коде функции Python.
Использование клиента
Обычно выполняется привязка к реализации IDurableClient (DurableOrchestrationClient в Устойчивые функции версии 1.x), которая обеспечивает полный доступ ко всем API клиента оркестрации, поддерживаемым Устойчивые функции.
Обычно вы привязываетесь к классу DurableClientContext.
Чтобы получить доступ к объекту клиента, необходимо использовать пакет SDK для конкретного языка.
В следующем коде представлен пример функции, активируемой очередью, которая запускает оркестрацию Hello World.
[FunctionName("QueueStart")]
public static Task Run(
[QueueTrigger("durable-function-trigger")] string input,
[DurableClient] IDurableOrchestrationClient starter)
{
// Orchestration input comes from the queue message content.
return starter.StartNewAsync<string>("HelloWorld", input);
}
Note
Предыдущий код C# предназначен для Устойчивые функции 2.x. Для Устойчивые функции 1.x необходимо использовать атрибут OrchestrationClient вместо атрибута DurableClient и использовать тип параметра DurableOrchestrationClient вместо IDurableOrchestrationClient. Дополнительные сведения о различиях между версиями см. в обзоре версий Устойчивые функции.
const { app } = require('@azure/functions');
const df = require('durable-functions');
app.storageQueue('helloQueueStart', {
queueName: 'start-orchestration',
extraInputs: [df.input.durableClient()],
handler: async (message, context) => {
const client = df.getClient(context);
const orchestratorName = message.orchestratorName || 'helloOrchestrator';
const input = message.input || null;
const instanceId = await client.startNew(orchestratorName, { input });
context.log(`Started orchestration with ID = '${instanceId}' from queue message.`);
},
});
import azure.functions as func
import azure.durable_functions as df
myApp = df.DFApp(http_auth_level=func.AuthLevel.ANONYMOUS)
@myApp.queue_trigger(
arg_name="msg",
queue_name="start-orchestration",
connection="AzureWebJobsStorage"
)
@myApp.durable_client_input(client_name="client")
async def client_function(msg: func.QueueMessage, client: df.DurableOrchestrationClient):
input_data = msg.get_body().decode("utf-8")
await client.start_new("my_orchestrator", None, input_data)
return None
function.json
{
"bindings": [
{
"name": "InputData",
"type": "queueTrigger",
"queueName": "durable-function-trigger",
"direction": "in"
},
{
"name": "starter",
"type": "durableClient",
"direction": "in"
}
]
}
run.ps1
param([string]$InputData, $TriggerMetadata)
$InstanceId = Start-DurableOrchestration -FunctionName 'HelloWorld' -Input $InputData
@FunctionName("QueueStart")
public void queueStart(
@QueueTrigger(name = "input", queueName = "durable-function-trigger", connection = "Storage") String input,
@DurableClientInput(name = "durableContext") DurableClientContext durableContext) {
// Orchestration input comes from the queue message content.
durableContext.getClient().scheduleNewOrchestrationInstance("HelloWorld", input);
}
Чтобы получить подробную информацию о запуске экземпляров, см. раздел Управление экземплярами в Устойчивые функции на Azure.
Триггер сущности
Триггер сущности можно использовать для разработки функции сущности. Этот триггер поддерживает обработку событий для конкретного экземпляра сущности.
Note
Триггеры сущностей доступны начиная с Устойчивые функции 2.x.
Внутренне, эта триггерная привязка инспектирует настроенное длительно сохраняющее хранилище для новых операций сущностей, которые необходимо выполнить.
Для настройки триггера сущности используется атрибут EntityTriggerAttribute .NET.
Чтобы зарегистрировать триггер сущности, импортируйте объект app из модуля @azure/functions npm. Затем вы вызываете app.entity метод API устойчивых функций непосредственно в коде функции.
const df = require('durable-functions');
df.app.entity('counter', (context) => {
const currentValue = context.df.getState(() => 0);
switch (context.df.operationName) {
case 'add':
context.df.setState(currentValue + context.df.getInput());
break;
case 'reset':
context.df.setState(0);
break;
case 'get':
context.df.return(currentValue);
break;
}
});
Триггер сущности можно определить с помощью заметки @DurableEntityTrigger . Используйте EntityRunner.loadAndRun, чтобы направлять операции в класс вашей сущности.
import com.microsoft.durabletask.AbstractTaskEntity;
import com.microsoft.durabletask.TaskEntityOperation;
import com.microsoft.durabletask.azurefunctions.DurableEntityTrigger;
import com.microsoft.durabletask.EntityRunner;
public class CounterEntity extends AbstractTaskEntity<Integer> {
public void add(int value) {
this.state += value;
}
public int get() {
return this.state;
}
public void reset() {
this.state = 0;
}
@Override
protected Integer initializeState(TaskEntityOperation operation) {
return 0;
}
@Override
protected Class<Integer> getStateType() {
return Integer.class;
}
}
// Entity function
@FunctionName("Counter")
public String counterEntity(
@DurableEntityTrigger(name = "req") String req) {
return EntityRunner.loadAndRun(req, CounterEntity::new);
}
Note
Триггеры сущностей пока не поддерживаются для PowerShell.
Триггер сущности можно определить с помощью декоратора entity_trigger непосредственно в коде функции Python.
Поведение триггера
Несколько заметок о триггере объекта:
- Однопоточный режим: один поток диспетчера используется для обработки операций для конкретной сущности. Если несколько сообщений отправляются в одну сущность одновременно, операции обрабатываются одновременно.
- Обработка подозрительных сообщений: в триггерах сущностей нет поддержки подозрительных сообщений.
- Видимость сообщения: сообщения триггера сущности выталкиваются из очереди и остаются невидимыми на заданное время. Видимость этих сообщений обновляется автоматически, пока приложение-функция работает исправно.
- Возвращаемые значения: функции сущностей не поддерживают возвращаемые значения. Существуют специфические API, которые можно использовать для сохранения состояния, или передачи значений обратно в оркестрации.
Все изменения состояния, внесенные в сущность во время его выполнения, автоматически сохраняются после завершения выполнения.
Дополнительные сведения и примеры определения и взаимодействия с триггерами сущностей см. в разделе "Функции сущности".
Клиент организации
Вы можете использовать привязку клиента сущности для асинхронной активации функций сущностей. Эти функции иногда называются клиентскими функциями.
Вы можете привязаться к клиенту сущности с помощью атрибута DurableClientAttribute .NET в функциях библиотеки классов .NET.
Note
Вы также можете использовать [DurableClientAttribute] для привязки к клиенту оркестрации.
Вместо регистрации клиента сущности, вы используете signalEntity или callEntity, чтобы вызвать метод триггера сущности из любой зарегистрированной функции.
Из функции, триггеруемой очередью, можно использовать
client.signalEntity:const { app } = require('@azure/functions'); const df = require('durable-functions'); app.storageQueue('helloQueueStart', { queueName: 'start-orchestration', extraInputs: [df.input.durableClient()], handler: async (message, context) => { const client = df.getClient(context); const entityId = new df.EntityId('counter', 'myCounter'); await client.signalEntity(entityId, 'add', 5); }, });Из функции оркестратора можно использовать
context.df.callEntity:const { app } = require('@azure/functions'); const df = require('durable-functions'); df.app.orchestration('entityCaller', function* (context) { const entityId = new df.EntityId('counter', 'myCounter'); yield context.df.callEntity(entityId, 'add', 5); yield context.df.callEntity(entityId, 'add', 5); const result = yield context.df.callEntity(entityId, 'get'); return result; });
Клиентский объект сущности можно определить с помощью декоратора durable_client_input непосредственно в коде функции Python.
Можно использовать аннотацию @DurableClientInput для привязки к DurableClientContext, который предоставляет методы для отправки сигналов сущностям и чтения состояния сущностей.
Отправка сигнала сущности из функции, запускаемой по HTTP-триггеру:
@FunctionName("SignalCounter") public HttpResponseMessage signalCounter( @HttpTrigger(name = "req", methods = {HttpMethod.POST}, authLevel = AuthorizationLevel.ANONYMOUS) HttpRequestMessage<Void> request, @DurableClientInput(name = "durableContext") DurableClientContext durableContext) { EntityInstanceId entityId = new EntityInstanceId("Counter", "myCounter"); durableContext.signalEntity(entityId, "add", 5); return request.createResponseBuilder(HttpStatus.ACCEPTED) .body("Signal sent") .build(); }Чтение состояния сущности из функции, запускаемой по HTTP-запросу:
@FunctionName("GetCounter") public HttpResponseMessage getCounter( @HttpTrigger(name = "req", methods = {HttpMethod.GET}, authLevel = AuthorizationLevel.ANONYMOUS) HttpRequestMessage<Void> request, @DurableClientInput(name = "durableContext") DurableClientContext durableContext) { EntityInstanceId entityId = new EntityInstanceId("Counter", "myCounter"); EntityMetadata metadata = durableContext.getEntityMetadata(entityId, true); if (metadata == null) { return request.createResponseBuilder(HttpStatus.NOT_FOUND).build(); } Integer state = metadata.readStateAs(Integer.class); return request.createResponseBuilder(HttpStatus.OK) .body(state) .build(); }
Note
Клиенты сущностей пока не поддерживаются для PowerShell.
Дополнительные сведения и примеры взаимодействия с сущностями в качестве клиента см. в разделе "Доступ".