Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Расширение Устойчивых функций вводит три привязки-триггеры, которые управляют выполнением функций оркестратора, действий и сущностей. Она также вводит выходную привязку, которая функционирует как клиент среды выполнения Durable Functions.
В этой статье рассматривается использование этих четырех привязок и приведены примеры кода.
Выберите язык разработки устойчивых функций в верхней части статьи.
Обе версии модели программирования Python для функций Azure поддерживаются устойчивыми функциями. Так как Python v2 является рекомендуемой, примеры в этой статье представлены исключительно в этой версии.
Необходимые условия
- пакет SDK Durable Functions, который является пакетом Индекса пакетов Python (PyPI)
azure-functions-durable, версии1.2.2или более поздней - Пакет расширений версии 4.x (или более поздняя версия), который устанавливается в файле проекта host.json
Вы можете предоставить отзывы и предложения в пакете SDK Durable Functions для репозитория Python.
Триггер оркестрации
Триггер оркестрации можно использовать для разработки устойчивых функций оркестратора. Этот триггер выполняется в момент, когда планируется новый экземпляр оркестрации, и в момент, когда существующий экземпляр оркестрации получает событие. Примеры событий, которые могут активировать функции оркестратора, включают истечения срока действия долговечного таймера, ответы функций активности и события, вызываемые внешними клиентами.
При разработке функций в .NET используйте атрибут OrchestrationTriggerAttribute .NET для настройки триггера оркестрации.
Для Java вы используете аннотацию @DurableOrchestrationTrigger для настройки триггера оркестрации.
При использовании версии 4 модели программирования Node.js для разработки функций вы импортируете app объект из @azure/functions npm модуля. Затем вы вызываете app.orchestration метод API устойчивых функций непосредственно в коде функции. Этот метод регистрирует функцию оркестратора с помощью платформы Durable Functions.
При записи функций оркестратора необходимо определить триггер оркестрации с помощью следующего объекта 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 вы получаете доступ к триггерам и привязкам в рамках Durable Functions из экземпляра DFApp. Этот подкласс FunctionApp можно использовать для экспорта декораторов, специфических для Durable Functions.
Внутри этого триггера привязка проверяет настроенное долгосрочное хранилище на наличие новых событий управления оркестрацией. Примеры событий включают события запуска оркестрации, события истечения срока действия таймера, события ответа функции активности и внешние события, вызванные другими функциями.
Поведение триггера
Ниже приведены некоторые заметки о триггере оркестрации:
- Однопоточность: Один диспетчерский поток используется для выполнения всех функций оркестратора в одном узле. По этой причине важно убедиться, что код функции оркестратора эффективен и не выполняет никаких операций ввода-вывода. Кроме того, важно убедиться, что этот поток не выполняет асинхронную работу, за исключением случаев ожидания типов задач, относящихся к устойчивым функциям.
- Обработка ядовитых сообщений: в триггерах оркестрации нет поддержки ядовитых сообщений.
- Видимость сообщений: оркестрационные триггерные сообщения извлекаются из очереди и остаются невидимыми в течение настраиваемой длительности. Видимость этих сообщений обновляется автоматически, пока приложение-функция работает исправно.
- Возвращаемые значения: возвращаемые значения сериализуются в 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}!";
}
Замечание
Предыдущий код предназначен для Durable Functions 2.x. Для Durable Functions 1.x необходимо использовать DurableOrchestrationContext вместо IDurableOrchestrationContext. Дополнительные сведения о различиях между версиями см. в обзоре версий Durable Functions.
const { app } = require('@azure/functions');
const df = require('durable-functions');
df.app.orchestration('helloOrchestrator', function* (context) {
const name = context.df.getInput();
return `Hello ${name}`;
});
Замечание
Библиотека 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;
}
Замечание
Предыдущий код предназначен для Durable Functions 2.x. Для Durable Functions 1.x необходимо использовать DurableOrchestrationContext вместо IDurableOrchestrationContext. Дополнительные сведения о различиях между версиями см. в обзоре версий Durable Functions.
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 для Durable Functions 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 Event Hubs.
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 в Durable Functions 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— это имя параметра приложения, содержащего строку подключения учетной записи хранения. Учетная запись хранения, представленная этой строкой подключения, должна совпадать с той, которую используют целевые функции оркестратора. Если это свойство не указано, используется строка подключения учетной записи хранения по умолчанию для функционального приложения.
Замечание
В большинстве случаев рекомендуется опустить эти свойства и полагаться на поведение по умолчанию.
Вы можете определить устойчивый триггер клиента с помощью декоратора durable_client_input непосредственно в коде функции Python.
Использование клиента
Обычно выполняется привязка к реализации IDurableClient (DurableOrchestrationClient в Durable Functions версии 1.x), которая обеспечивает полный доступ ко всем API клиента оркестрации, поддерживаемым Durable Functions.
Обычно вы привязываетесь к классу 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);
}
Замечание
Предыдущий код C# предназначен для Durable Functions 2.x. Для Durable Functions 1.x необходимо использовать атрибут OrchestrationClient вместо атрибута DurableClient и использовать тип параметра DurableOrchestrationClient вместо IDurableOrchestrationClient. Дополнительные сведения о различиях между версиями см. в обзоре версий Durable Functions.
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);
}
Чтобы получить подробную информацию о запуске экземпляров, см. раздел Управление экземплярами в Durable Functions на Azure.
Триггер сущности
Триггер сущности можно использовать для разработки функции сущности. Этот триггер поддерживает обработку событий для конкретного экземпляра сущности.
Замечание
Триггеры сущностей доступны начиная с Durable Functions 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;
}
});
Замечание
Триггеры сущностей пока не поддерживаются для Java.
Замечание
Триггеры сущностей пока не поддерживаются для PowerShell.
Триггер сущности можно определить с помощью декоратора entity_trigger непосредственно в коде функции Python.
Поведение триггера
Несколько заметок о триггере объекта:
- Однопоточный режим: один поток диспетчера используется для обработки операций для конкретной сущности. Если несколько сообщений отправляются в одну сущность одновременно, операции обрабатываются одновременно.
- Обработка подозрительных сообщений: в триггерах сущностей нет поддержки подозрительных сообщений.
- Видимость сообщения: сообщения триггера сущности выталкиваются из очереди и остаются невидимыми на заданное время. Видимость этих сообщений обновляется автоматически, пока приложение-функция работает исправно.
- Возвращаемые значения: функции сущностей не поддерживают возвращаемые значения. Существуют специфические API, которые можно использовать для сохранения состояния, или передачи значений обратно в оркестрации.
Все изменения состояния, внесенные в сущность во время его выполнения, автоматически сохраняются после завершения выполнения.
Дополнительные сведения и примеры определения и взаимодействия с триггерами сущностей см. в разделе "Функции сущности".
Клиент организации
Вы можете использовать привязку клиента сущности для асинхронной активации функций сущностей. Эти функции иногда называются клиентскими функциями.
Вы можете привязаться к клиенту сущности с помощью атрибута DurableClientAttribute .NET в функциях библиотеки классов .NET.
Замечание
Вы также можете использовать [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.
Замечание
Клиенты сущностей пока не поддерживаются для Java.
Замечание
Клиенты сущностей пока не поддерживаются для PowerShell.
Дополнительные сведения и примеры взаимодействия с сущностями в качестве клиента см. в разделе "Доступ".