You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Azure Durable Function中持久化触发器传入的CorrelationId至所有日志

Durable Function编排器中CorrelationId持久化方案(解决AsyncLocal丢失问题)

问题根源

Durable Function编排器会被持久化并在后续重放,而AsyncLocal的上下文依赖于当前异步调用栈,重放时执行上下文重建,原有AsyncLocal值会丢失。必须借助Durable Functions原生的状态持久化机制来存储CorrelationId。

可行实现方案

1. 用OrchestrationContext自定义属性存储CorrelationId

OrchestrationContext的CustomProperties字典会被持久化到编排器状态中,重放时自动恢复,是最可靠的存储方式:

步骤1:在Service Bus触发器中传递CorrelationId到编排器

[FunctionName("ServiceBusTrigger")]
public async Task Run(
    [ServiceBusTrigger("myqueue", Connection = "ServiceBusConnection")] Message message,
    [DurableClient] IDurableOrchestrationClient client)
{
    var correlationId = message.CorrelationId;
    // 启动编排器时将CorrelationId作为输入传递
    await client.StartNewAsync("MyOrchestrator", input: correlationId);
}

步骤2:在编排器中存入自定义属性

[FunctionName("MyOrchestrator")]
public async Task RunOrchestrator(
    [OrchestrationTrigger] IDurableOrchestrationContext context)
{
    var correlationId = context.GetInput<string>();
    // 将CorrelationId存入持久化的自定义属性
    context.CustomProperties["CorrelationId"] = correlationId;

    // 调用活动函数,无需手动传递CorrelationId
    await context.CallActivityAsync("MyActivity", null);
}

步骤3:修改ITelemetryInitializer从上下文获取CorrelationId

public class CorrelationTelemetryInitializer : ITelemetryInitializer
{
    private readonly IDurableOrchestrationContext _orchestrationContext;
    private readonly IDurableActivityContext _activityContext;
    // 注入编排器/活动上下文(依赖注入会自动匹配当前执行环境)
    public CorrelationTelemetryInitializer(IDurableOrchestrationContext orchestrationContext = null, IDurableActivityContext activityContext = null)
    {
        _orchestrationContext = orchestrationContext;
        _activityContext = activityContext;
    }

    public void Initialize(ITelemetry telemetry)
    {
        string correlationId = null;

        // 编排器环境:直接从自定义属性取
        if (_orchestrationContext != null)
        {
            _orchestrationContext.CustomProperties.TryGetValue("CorrelationId", out var val);
            correlationId = val?.ToString();
        }
        // 活动函数环境:从关联的编排器上下文取
        else if (_activityContext != null)
        {
            _activityContext.OrchestrationContext.CustomProperties.TryGetValue("CorrelationId", out var val);
            correlationId = val?.ToString();
        }
        // 触发器/其他环境:保留原有AsyncLocal逻辑
        else
        {
            // 你的原有AsyncLocal取值逻辑
        }

        if (!string.IsNullOrEmpty(correlationId))
        {
            telemetry.Properties["CorrelationId"] = correlationId;
        }
    }
}

2. 活动函数中自动获取CorrelationId

活动函数无需手动接收CorrelationId,通过IDurableActivityContext直接访问编排器的自定义属性,日志会通过TelemetryInitializer自动带上该值:

[FunctionName("MyActivity")]
public void MyActivity(
    [ActivityTrigger] IDurableActivityContext context,
    ILogger logger)
{
    // 无需手动传递,直接从上下文获取(可选,若业务逻辑需要)
    var correlationId = context.OrchestrationContext.CustomProperties["CorrelationId"].ToString();
    logger.LogInformation("Activity executed with CorrelationId: {CorrelationId}", correlationId);
}

3. 备选:关联CorrelationId与InstanceId(不推荐)

若场景允许,可在启动编排器时将CorrelationId指定为InstanceId,但会丢失系统自动生成InstanceId的唯一性保证,仅适合CorrelationId本身唯一的场景:

// Service Bus触发器中
var instanceId = message.CorrelationId;
await client.StartNewAsync("MyOrchestrator", instanceId: instanceId);

此时可在TelemetryInitializer中直接取OrchestrationContext.InstanceId作为CorrelationId,但灵活性不如自定义属性。

注意事项

  • CustomProperties仅支持可序列化的基本类型(string、int等),不可存入复杂对象。
  • 编排器重放时,CustomProperties会自动从持久化状态恢复,无需额外处理。
  • 依赖注入会自动为编排器/活动函数注入对应的上下文,无需手动实例化。

内容的提问来源于stack exchange,提问作者ifg43

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 16:38:16