配置 Durable Functions 发布到 Azure 事件网格

将编排生命周期事件发布到 Azure 事件网格,可以实现 DevOps 自动化(例如蓝/绿部署)、实时监控仪表板以及跟踪长时间运行的后台进程。

注意

本指南使用.NET示例,但概念和Azure CLI命令适用于所有受支持的Durable Functions语言。

Tip

如果已配置事件网格自定义主题和托管标识,请跳到 配置Durable Functions发布者应用

先决条件

  • 部署到Azure的Durable Functions项目。 如果没有,请使用首选语言的快速入门创建一个:

  • 正确的Durable Functions扩展版本。 对于.NET,请将扩展更新到最新版本:

    • 2.7.0+ (进程内)

      dotnet add package Microsoft.Azure.WebJobs.Extensions.DurableTask
      
    • 1.1.0+ (隔离工作者)

      dotnet add package Microsoft.Azure.Functions.Worker.Extensions.DurableTask
      

    对于其他语言,请检查你的package.jsonrequirements.txtpom.xmlrequirements.psd1

  • 在您的函数应用中启用和配置了托管身份。

  • 正在运行的存储提供程序或本地 Azurite 存储模拟器

  • Azure CLI

  • 一个 HTTP 测试工具 ,用于保护数据安全。

创建自定义事件网格主题

可以使用 Azure CLIPowerShell Azure 门户创建事件网格主题,以便从Durable Functions发送事件。

本指南使用Azure CLI。

创建资源组

使用 az group create 命令创建资源组。 选择支持事件网格的位置,并匹配要在其中部署资源的位置。

注意

目前,Azure 事件网格不支持所有区域。 有关支持哪些区域的信息,请参阅 Azure 事件网格 概述

az group create --name <resource-group-name> --location <location>

启用事件网格资源提供者

  1. 如果这是首次在 Azure 订阅中使用事件网格,则可能需要注册事件网格资源提供程序。 运行以下命令,注册提供程序:

    az provider register --namespace Microsoft.EventGrid
    
  2. 完成注册可能需要一些时间。 若要查看状态,请运行以下命令:

    az provider show --namespace Microsoft.EventGrid --query "registrationState"
    

    registrationStateRegistered 后,即可继续。

创建自定义主题

事件网格主题提供用户定义的终结点,可向该终结点发布事件。 在以下命令中将 <topic-name> 替换为您主题的唯一名称。 主题名称必须是唯一的,因为它将成为 DNS 条目。

az eventgrid topic create --name <topic-name> --location <location> --resource-group <resource-group-name>

获取主题终结点

获取主题的终结点。 将以下命令中的 <topic-name> 替换为您选择的名称。

az eventgrid topic show --name <topic-name> --resource-group <resource-group-name> --query "endpoint" --output tsv

保存此终结点供以后使用。

Azure 中的托管标识允许资源在不存储凭据、简化安全性和标识管理的情况下向 Azure 服务进行身份验证。 将与 Durable Function 应用关联的托管标识分配给事件网格自定义主题。

配置Durable Functions发布者应用

尽管Durable Functions应用会自动将业务流程生命周期事件发布到事件网格,但需要配置连接设置。 将以下内容添加到 extensions.durableTask 以下 host.json部分中:

{
  "version": "2.0",
  "extensions": {
    "durableTask": {
      "eventGridTopicEndpoint": "%EventGrid__topicEndpoint%",
      "eventGridKeySettingName": "EventGrid__credential"
    }
  }
}

注意

eventGridTopicEndpoint 设置引用前面保存的事件网格自定义主题终结点。 凭据设置可同时处理托管身份和连接字符串场景。

分配事件网格数据发送者角色

授予 托管标识 将事件发布到 Event Grid 主题的权限。

az role assignment create \
  --assignee <client-id-of-managed-identity> \
  --assignee-principal-type ServicePrincipal \
  --role "EventGrid Data Sender" \
  --scope /subscriptions/<subscription-id>/resourceGroups/<resource-group-name>/providers/Microsoft.EventGrid/topics/<topic-name>

请替换以下值:

  • <client-id-of-managed-identity>:用户分配的托管标识的客户端 ID
  • <subscription-id>:Azure订阅 ID
  • <resource-group-name>:包含事件网格主题的资源组的名称
  • <topic-name>:事件网格主题的名称

注意

角色分配可能需要 5-10 分钟才能传播。 如果在分配后马上进行操作,可能会看到身份验证错误。

配置应用设置

为函数应用和主题启用托管标识后,请在Durable Functions函数应用上配置事件网格应用设置。

添加以下应用设置:

  • EventGrid__topicEndpoint — 事件网格主题终结点。
  • EventGrid__credential — 设置为 managedidentity.
  • EventGrid__clientId — 用户分配的托管身份客户端 ID。
az functionapp config appsettings set --name <function app name> --resource-group <resource group name> --settings EventGrid__topicEndpoint="<topic endpoint>" EventGrid__credential="managedidentity" EventGrid__clientId="<client id>"

订阅活动

若要接收已发布的生命周期事件,请创建一个 事件网格订阅 ,用于将事件从自定义主题路由到订阅服务器。 常见的订阅服务器类型包括Azure Functions(包含事件网格触发器)、逻辑应用和 Webhook。

以下示例使用Azure CLI创建具有事件网格触发器的订阅服务器函数应用。 如果您已经有订阅者,请跳到 创建事件网格订阅

创建侦听器函数应用

创建用于托管事件网格触发器的函数应用。 侦听器必须与事件网格主题位于同一区域。

# Create a resource group
az group create --name <listener-resource-group-name> --location <location>

# Create a storage account
az storage account create \
  --name <storage-account-name> \
  --resource-group <listener-resource-group-name> \
  --location <location> \
  --sku Standard_LRS \
  --allow-blob-public-access false

# Create the function app
az functionapp create \
  --resource-group <listener-resource-group-name> \
  --consumption-plan-location <location> \
  --runtime <preferred-runtime> \
  --functions-version 4 \
  --name <listener-function-app-name> \
  --storage-account <storage-account-name>

创建和部署事件网格触发器函数

搭建本地项目、添加事件网格触发器并发布它:

mkdir EventGridListenerFunction && cd EventGridListenerFunction
func init --name EventGridListener --runtime dotnet-isolated
func new --template "Event Grid trigger" --name EventGridTrigger
func azure functionapp publish <listener-function-app-name>

注意

dotnet-isolated 替换为您首选的运行时(nodepythonjavapowershell). 有关详细的部署说明,请参阅 Publish 到 Azure

创建事件网格订阅

使用 azurefunction 终结点类型创建订阅,该类型会自动处理 Webhook 验证:

az eventgrid event-subscription create \
  --name <subscription-name> \
  --source-resource-id /subscriptions/<subscription-id>/resourceGroups/<resource-group-name>/providers/Microsoft.EventGrid/topics/<topic-name> \
  --endpoint /subscriptions/<subscription-id>/resourceGroups/<listener-resource-group-name>/providers/Microsoft.Web/sites/<listener-function-app-name>/functions/EventGridTrigger \
  --endpoint-type azurefunction

Tip

建议将 --endpoint-type azurefunction 与函数的资源 ID 一起使用。 它能够自动处理 Webhook 的验证,比使用带有 URL 的 --endpoint-type webhook 更加可靠。

事件架构

当业务流程状态发生更改时,Durable Functions运行时会发布具有以下结构的事件。 为每个状态转换自动生成事件 - 无需添加任何代码。

领域 说明
id 事件网格事件的唯一标识符。
subject durable/orchestrator/{orchestrationRuntimeStatus}— 状态可以是RunningCompletedFailedTerminated
eventType 始终为 orchestratorEvent
eventTime 事件时间(UTC)。
data.hubName TaskHub 名称。
data.functionName Orchestrator 函数名称。
data.instanceId 唯一的编排实例 ID。
data.runtimeStatus RunningCompletedFailedCanceled.
data.reason 其他跟踪数据。 有关详细信息,请参阅 Durable Functions 中的 Diagnostics

事件网格可确保至少传递一次,因此你可能会在极少数故障情况下收到重复事件。 请考虑根据需要添加 instanceId 去重逻辑。

验证事件传递

若要验证端到端设置,请部署 Durable Functions 应用并触发一次协调运行:

  1. 发布函数代码到Azure,然后验证函数应用在Azure门户中显示“正在运行”。

  2. 在 Azure 门户中,在 设置>环境变量 下验证你的应用设置EventGrid__topicEndpoint和(如果使用托管身份)EventGrid__credential

  3. 使用 HTTP 客户端触发编排流程:

    curl -X POST https://<function_app_name>.chinacloudsites.cn/api/HelloOrchestration_HttpStart
    
  4. 在 Azure 门户中,导航到 listener 函数应用>EventGridTrigger>Monitor以查看收到的事件。 你应该会看到主题类似于durable/orchestrator/Runningdurable/orchestrator/Completed的事件。

在 Application Insights 中验证(可选)

若需更全面的视图,请在函数应用的 Application Insights 日志中运行此 KQL 查询。

traces
| where message contains "Event type" or message contains "Event subject"
| project timestamp, message
| order by timestamp desc

故障排除

事件未发布到事件网格

问题:侦听器函数未接收事件。

解决方法

  • 验证Durable Functions函数应用是否具有正确的应用设置:
    • EventGrid__topicEndpoint 必须指向自定义主题终结点
    • EventGrid__credential 必须设置为 managedidentity
    • EventGrid__clientId 如果使用用户分配的标识,则必须设置
  • 验证托管标识是否具有分配给事件网格自定义主题的 EventGrid 数据发送者 角色。
  • 检查 Application Insights 中的Durable Functions函数应用日志是否存在错误。
  • 验证事件网格主题是否存在并且在同一订阅中可访问。

未触发监听器函数

问题:侦听器函数存在,但在发布事件时未执行。

解决方法

  • 验证是否已创建事件网格订阅并已启用:
    • 在 Azure 门户中,导航到事件网格主题 → Subscriptions
    • 确认侦听器函数的订阅状态 已列出为“已启用”
  • 验证事件网格订阅是否使用正确的终结点类型:
    • 对于 Azure Functions,请结合函数的资源 ID 使用 --endpoint-type azurefunction
    • 如果使用 --endpoint-type webhook,请确保 Webhook URL 格式正确: https://<function-app>.chinacloudsites.cn/runtime/webhooks/eventgrid?functionName=<function-name>&code=<system-key>
  • 检查侦听器函数应用日志中是否存在错误或传递问题。
  • 在事件网格主题→ 指标中,检查是否存在可能指示传递失败的 已删除事件

日志中的“禁止访问”或身份验证错误

问题:发布到事件网格时的身份验证错误。

解决方法

  • 验证托管身份是否已正确配置并在 Durable Functions 函数应用上启用:
    • 在 Azure 门户中,导航到函数应用 → Identity
    • 请确认“状态”显示为 开启,无论是系统分配标识还是用户分配标识。
  • 验证角色分配是否正确:
    • 导航到您的事件网格主题 → 访问控制(IAM)
    • 确认托管标识具备 EventGrid 数据发送方 角色(注意:“Event”和“Grid”之间无空格)
    • 角色分配可能需要 5-10 分钟才能生效

“连接被拒绝”或“找不到终结点”错误

问题:事件网格主题的连接错误。

解决方法

  • 验证应用设置中的事件网格主题终结点是否正确,并包含完整的 URL(例如) https://my-topic.eventgrid.chinacloudapi.cn/api/events
  • 验证同一订阅和区域中是否存在事件网格主题资源
  • 检查Durable Functions应用是否对事件网格终结点具有网络访问权限

在本地测试

若要在本地进行测试,请参阅 使用查看器 Web 应用的本地测试。 使用托管标识在本地测试时,请使用开发人员凭据对事件网格主题进行身份验证。 有关详细信息,请参阅 使用托管标识配置Durable Functions - 本地开发

清理资源

如果不打算继续使用本教程中创建的资源,请将其删除以避免产生费用。

删除资源组

删除资源组及其包含的所有资源:

az group delete --name <resource-group-name> --yes
az group delete --name <listener-resource-group-name> --yes

删除单个资源

如果要保留某些资源,可以单独删除它们:

  1. 删除事件网格订阅:

    az eventgrid event-subscription delete \
      --name <subscription-name> \
      --source-resource-id /subscriptions/<subscription-id>/resourceGroups/<resource-group-name>/providers/Microsoft.EventGrid/topics/<topic-name>
    
  2. 删除事件网格主题:

    az eventgrid topic delete --name <topic-name> --resource-group <resource-group-name>
    
  3. 删除函数应用:

    az functionapp delete --name <publisher-function-app-name> --resource-group <resource-group-name>
    az functionapp delete --name <listener-function-app-name> --resource-group <listener-resource-group-name>
    
  4. 删除存储帐户:

    az storage account delete --name <storage-account-name> --resource-group <resource-group-name> --yes
    az storage account delete --name <listener-storage-account-name> --resource-group <listener-resource-group-name> --yes
    

后续步骤

了解有关以下方面的详细信息: