Compartilhar via

在 Durable Functions 中处理外部事件 (Azure Functions)

协调器函数能够等待和侦听外部事件。 Durable Functions 的此功能对于处理人机交互或其他外部触发器通常比较有用。

注意

外部事件是单向的异步操作。 它们不适用于发送事件的客户端需要来自业务流程协调程序函数的同步响应的情况。

等待事件

业务流程触发器绑定的“wait-for-external-event”API 使业务流程协调程序函数可异步等待和侦听外部客户端传递的事件。 监听器编排器功能声明了事件的“名称”和它期望收到的“数据结构”。

[FunctionName("BudgetApproval")]
public static async Task Run(
    [OrchestrationTrigger] IDurableOrchestrationContext context)
{
    bool approved = await context.WaitForExternalEvent<bool>("Approval");
    if (approved)
    {
        // approval granted - do the approved action
    }
    else
    {
        // approval denied - send a notification
    }
}

注意

前面的 C# 代码适用于 Durable Functions 2.x。 对于 Durable Functions 1.x,必须使用 DurableOrchestrationContext 而不是 IDurableOrchestrationContext。 有关版本之间差异的详细信息,请参阅 Durable Functions 版本一文。

前面的示例侦听特定单个事件,并在收到该事件时执行操作。

可以同时侦听多个事件,例如以下示例会等待三个可能的事件通知中的一个。

[FunctionName("Select")]
public static async Task Run(
    [OrchestrationTrigger] IDurableOrchestrationContext context)
{
    var event1 = context.WaitForExternalEvent<float>("Event1");
    var event2 = context.WaitForExternalEvent<bool>("Event2");
    var event3 = context.WaitForExternalEvent<int>("Event3");

    var winner = await Task.WhenAny(event1, event2, event3);
    if (winner == event1)
    {
        // ...
    }
    else if (winner == event2)
    {
        // ...
    }
    else if (winner == event3)
    {
        // ...
    }
}

注意

前面的 C# 代码适用于 Durable Functions 2.x。 对于 Durable Functions 1.x,必须使用 DurableOrchestrationContext 而不是 IDurableOrchestrationContext。 有关版本之间差异的详细信息,请参阅 Durable Functions 版本一文。

前面的示例侦听多个事件中的任意事件。 还可以等待所有事件。

[FunctionName("NewBuildingPermit")]
public static async Task Run(
    [OrchestrationTrigger] IDurableOrchestrationContext context)
{
    string applicationId = context.GetInput<string>();

    var gate1 = context.WaitForExternalEvent("CityPlanningApproval");
    var gate2 = context.WaitForExternalEvent("FireDeptApproval");
    var gate3 = context.WaitForExternalEvent("BuildingDeptApproval");

    // all three departments must grant approval before a permit can be issued
    await Task.WhenAll(gate1, gate2, gate3);

    await context.CallActivityAsync("IssueBuildingPermit", applicationId);
}

注意

前面的代码适用于 Durable Functions 2.x。 对于 Durable Functions 1.x,必须使用 DurableOrchestrationContext 而不是 IDurableOrchestrationContext。 有关版本之间差异的详细信息,请参阅 Durable Functions 版本一文。

在 .NET 中,如果事件负载无法转换为预期类型 T,将会引发异常。

“wait-for-external-event” API 无期限地等待一些输入。 在等待时,可以安全地卸载功能应用。 对于此编排实例,当某个事件到达时,会立即被自动唤醒并处理该事件。

注意

如果函数应用使用消耗计划,当业务流程协调程序函数等待外部事件任务时,无论它等待多久,都不会产生账单费用。

与活动函数一样,外部事件具有至少一次交付保证。 这意味着,在某些条件下(例如重启、缩放、崩溃等),应用程序可能会收到重复的同一外部事件。 因此,我们建议外部事件包含某种 ID,以便在业务流程协调程序中手动取消其重复。

发送事件

可使用由编排客户端绑定定义的“raise-event”API将外部事件发送到编排。 还可以使用内置引发事件 HTTP API 将外部事件发送到业务流程。

引发的事件包括实例 ID、eventName 和 eventData 等参数。 业务流程协调器函数使用“wait-for-external-event” API 处理这些事件。 在发送端和接收端,eventName 必须匹配才能处理事件。 事件数据还必须是 JSON 可序列化的。

在内部,“raise-event”机制将消息排入队列,随后会被正在等待的协调器函数选取。 如果实例没有在等待指定的事件名,则将事件消息添加到内存中队列。 如果编排实例稍后开始侦听该事件名称,它将检查队列中的事件消息。

注意

如果没有具有指定实例 ID 的业务流程实例,则丢弃事件消息。

下面是一个队列触发函数的示例,它将“Approval”事件发送到一个协调器函数实例。 编排实例 ID 来自队列消息的正文。

[FunctionName("ApprovalQueueProcessor")]
public static async Task Run(
    [QueueTrigger("approval-queue")] string instanceId,
    [DurableClient] IDurableOrchestrationClient client)
{
    await client.RaiseEventAsync(instanceId, "Approval", true);
}

注意

前面的 C# 代码适用于 Durable Functions 2.x。 对于 Durable Functions 1.x,必须使用 OrchestrationClient 属性而不是 DurableClient 属性,并且必须使用 DurableOrchestrationClient 参数类型而不是 IDurableOrchestrationClient。 有关版本之间差异的详细信息,请参阅 Durable Functions 版本一文。

在内部,“raise-event”API 会将消息排入队列,供在等待的协调函数处理。 如果实例没有在等待指定的事件名,则将事件消息添加到内存缓冲区。 如果编排实例稍后开始侦听“事件名称”,它将检查缓冲区中的事件消息,并触发正在等待的任务。

注意

如果没有具有指定实例 ID 的业务流程实例,则丢弃事件消息。

HTTP

以下是一个 HTTP 请求示例,该请求向协调实例引发“批准”事件。

POST /runtime/webhooks/durabletask/instances/MyInstanceId/raiseEvent/Approval&code=XXX
Content-Type: application/json

"true"

在本例中,实例 ID 硬编码为 MyInstanceId。

后续步骤