你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

业务流程版本控制(预览版)

使用持久业务流程系统时,升级和降级业务流程是一个关键的考虑因素。 当自动化流程被中断后恢复时(例如,在主机更新期间),Durable Task Scheduler 将重播自动化流程中的事件,确保在执行下一步之前,所有以前的步骤均已成功执行。 此作可确保可靠性,这是持久执行范例的核心承诺之一。

如果业务流程在部署之间发生更改,则执行的步骤可能不再相同。 在这种情况下,系统会抛出一个NonDeterministicError,而不是允许编排继续进行。

业务流程版本控制 可防止与不确定相关的问题,使你能够与新的(或旧)业务流程无缝协作。 持久任务计划程序具有两种不同的版本控制样式,可以单独使用或结合使用:

重要

目前,持久任务 SDK 不适用于 JavaScript 和 PowerShell。

重要

目前,持久任务 SDK 不适用于 JavaScript 和 PowerShell。

基于客户端/上下文的条件版本控制

为了使业务流程具有版本,你必须先在客户端中设置业务流程。

.NET SDK 使用标准主机生成器扩展。

注释

自 v1.9.0 起在 .NET SDK 中Microsoft.DurableTask.Client.AzureManaged可用。

builder.Services.AddDurableTaskClient(builder =>
{
    builder.UseDurableTaskScheduler(connectionString);
    builder.UseDefaultVersion("1.0.0");
});

注释

自 v1.6.0 起在 Java SDK (com.microsoft:durabletask-client) 中提供。

public DurableTaskClient durableTaskClient(DurableTaskProperties properties) {
    // Create client using Azure-managed extensions
    return DurableTaskSchedulerClientExtensions.createClientBuilder(properties.getConnectionString())
        .defaultVersion("1.0")
        .build();
}
 c = DurableTaskSchedulerClient(host_address=endpoint, secure_channel=secure_channel,
                                   taskhub=taskhub_name, token_credential=credential,
                                   default_version="1.0.0")

将版本添加到客户端后,此主机启动的任何业务流程都使用该版本 1.0.0。 版本是一个简单的字符串,接受任何值。 但是,SDK 会尝试将其转换为 。NET 的 System.Version

  • 如果 可以 转换,则使用该库进行比较。
  • 如果没有 则使用简单的字符串比较。

在客户端中提供版本也会使版本在 TaskOrchestrationContext中可用,这意味着您可以在条件语句中使用该版本。 只要较新的业务流程版本具有适当的版本限制,旧业务流程版本和新业务流程版本都可以在同一主机上一起运行。

Example:

[DurableTask]
class HelloCities : TaskOrchestrator<string, List<string>>
{
    private readonly string[] Cities = ["Seattle", "Amsterdam", "Hyderabad", "Kuala Lumpur", "Shanghai", "Tokyo"];

    public override async Task<List<string>> RunAsync(TaskOrchestrationContext context, string input)
    {
        List<string> results = [];
        foreach (var city in Cities)
        {
            results.Add(await context.CallSayHelloAsync($"{city} v{context.Version}"));
            if (context.CompareVersionTo("2.0.0") >= 0)
            {
                results.Add(await context.CallSayGoodbyeAsync($"{city} v{context.Version}"));
            }
        }

        Console.WriteLine("HelloCities orchestration completed.");
        return results;
    }
}

将版本添加到客户端后,此客户端启动的任何业务流程都使用该版本 1.0.0。 版本是一个简单的字符串,接受任何值。

在客户端中提供的版本也在 TaskOrchestration 中可用,这意味着你可以在条件语句中使用该版本。 只要较新的业务流程版本具有适当的版本限制,旧业务流程版本和新业务流程版本都可以在同一客户端上运行。

Example:

public TaskOrchestration create() {
    return ctx -> {
        List<String> results = new ArrayList<>();
        for (String city : new String[]{ "Seattle", "Amsterdam", "Hyderabad", "Kuala Lumpur", "Shanghai", "Tokyo" }) {
            results.add(ctx.callActivity("SayHello", city, String.class).await());
            if (VersionUtils.compareVersions(ctx.getVersion(), "2.0.0") >= 0) {
                // Simulate a delay for newer versions
                results.add(ctx.callActivity("SayGoodbye", city, String.class).await());
            }
        }
        ctx.complete(results);
    };
}

将版本添加到客户端后,此客户端启动的任何业务流程都使用该版本 1.0.0。 版本是一个使用packaging.version解析的简单字符串,它支持语义版本控制比较,并接受任何值。

在客户端中提供版本也使其在task.OrchestrationContext中可用,这意味着你可以在条件语句中使用该版本。 只要较新的业务流程版本具有适当的版本限制,旧业务流程版本和新业务流程版本都可以在同一客户端上运行。

Example:

def orchestrator(ctx: task.OrchestrationContext, _):
    if ctx.version == "1.0.0":
        # For version 1.0.0, we use the original logic
        result: int = yield ctx.call_activity(activity_v1, input="input for v1")
    elif ctx.version == "2.0.0":
        # For version 2.0.0, we use the updated logic
        result: int = yield ctx.call_activity(activity_v2, input="input for v2")
    else:
        raise ValueError(f"Unsupported version: {ctx.version}")
    return {
        'result': result,
    }

在此示例中,我们已向 HelloCities 业务流程中添加了一个 SayGoodbye 活动。 此活动仅在编排版本 2.0.0 及更高版本中调用。 使用简单条件语句时,任何版本小于 2.0.0 的编排将继续运行,并且任何新的编排都包含新的活动。

何时使用客户端版本控制

虽然客户端版本控制为版本控制业务流程提供了最简单的机制,但与版本交互可能会占用大量编程。 在以下的情况下使用客户端版本控制:

  • 你想要一个适用于所有版本的标准版本,还是
  • 您需要针对特定版本设计自定义逻辑。

基于工作线程的版本控制

虽然业务流程仍然需要客户端版本来设置版本,但基于工作线程的版本控制方法有助于避免在业务流程中使用条件语句。 工作线程选择如何在开始执行之前处理不同版本的业务流程。

工作者版本控制需设置以下字段:

  1. 工作线程的版本。

  2. 应用于工作线程启动的子业务流程的默认版本。

  3. 工作线程匹配业务流程版本所使用的策略。

    名称 DESCRIPTION
    没有 处理工作时不考虑版本
    严格 业务流程中的版本和辅助角色必须完全匹配
    当前或更早版本 业务流程中的版本必须等于或小于辅助角色中的版本
  4. 版本不符合匹配策略时工作线程所采取的策略。

    名称 DESCRIPTION
    拒绝 该业务流程已被工作线程拒绝,但仍保留在工作队列中,以便稍后再次尝试该业务流程。
    失败 此业务流程已失败并从工作队列中移除

与客户端版本控制类似,可以通过标准主机生成器模式设置这些字段。

注释

自 v1.9.0 起,在 .NET SDK(Microsoft.DurableTask.Worker.AzureManaged)中可用。

builder.Services.AddDurableTaskWorker(builder =>
{
    builder.AddTasks(r => r.AddAllGeneratedTasks());
    builder.UseDurableTaskScheduler(connectionString);
    builder.UseVersioning(new DurableTaskWorkerOptions.VersioningOptions
    {
        Version = "1.0.0",
        DefaultVersion = "1.0.0",
        MatchStrategy = DurableTaskWorkerOptions.VersionMatchStrategy.Strict,
        FailureStrategy = DurableTaskWorkerOptions.VersionFailureStrategy.Reject,
    });
});

注释

自 v1.6.0 起,Java SDK(com.microsoft:durabletask-client)中提供。

private static DurableTaskGrpcWorker createTaskHubServer() {
    DurableTaskGrpcWorkerBuilder builder = new DurableTaskGrpcWorkerBuilder();
    builder.useVersioning(new DurableTaskGrpcWorkerVersioningOptions(
            "1.0",
            "1.0",
            DurableTaskGrpcWorkerVersioningOptions.VersionMatchStrategy.CURRENTOROLDER,
            DurableTaskGrpcWorkerVersioningOptions.VersionFailureStrategy.REJECT));

    // Orchestrations can be defined inline as anonymous classes or as concrete classes
    builder.addOrchestration(new TaskOrchestrationFactory() {
        @Override
        public String getName() { return "HelloCities"; }

        @Override
        public TaskOrchestration create() {
            return ctx -> {
                List<String> results = new ArrayList<>();
                for (String city : new String[]{ "Seattle", "Amsterdam", "Hyderabad", "Kuala Lumpur", "Shanghai", "Tokyo" }) {
                    results.add(ctx.callActivity("SayHello", city, String.class).await());
                }
                ctx.complete(results);
            };
        }
    });

    // Activities can be defined inline as anonymous classes or as concrete classes
    builder.addActivity(new TaskActivityFactory() {
        @Override
        public String getName() { return "SayHello"; }

        @Override
        public TaskActivity create() {
            return ctx -> {
                String input = ctx.getInput(String.class);
                return "Hello, " + input + "!";
            };
        }
    });

    return builder.build();
}
with DurableTaskSchedulerWorker(host_address=endpoint, secure_channel=secure_channel,
                                taskhub=taskhub_name, token_credential=credential) as w:
    # This worker is versioned for v2, as the orchestrator code has already been updated
    # CURRENT_OR_OLDER allows this worker to process orchestrations versioned below 2.0.0 - e.g. 1.0.0
    w.use_versioning(worker.VersioningOptions(
        version="2.0.0",
        default_version="2.0.0",
        match_strategy=worker.VersionMatchStrategy.CURRENT_OR_OLDER,
        failure_strategy=worker.VersionFailureStrategy.FAIL
    ))
    w.add_orchestrator(orchestrator)
    w.add_activity(activity_v1)
    w.add_activity(activity_v2)
    w.start()

失败策略

拒绝

当期望的行为是让业务流程稍后或针对其他工作线程重试时,使用 Reject 故障策略。 在 Reject 故障期间:

  1. 业务流程被拒绝并返回到工作队列。
  2. 业务流程已取消排队。
  3. 取消排队的业务流程可能会落到其他工作线程上,也可能会再次落到同一工作线程上。

此过程将重复,直到可处理业务流程的工作线程可用为止。 此策略可无缝处理业务流程更新所在的部署。 随着部署的进行,无法处理业务流程的工作线程会拒绝此业务流程,而能够处理业务流程的工作线程会处理此业务流程。

利用混合使用工作线程和业务流程版本的功能,使得蓝绿部署等方案成为可能。

失败

不需要其他版本时,请使用 Fail 故障策略。 在这种情况下,新版本是一个异常,任何工作者甚至都不应该尝试操作它。 持久任务计划程序未成功执行业务流程,使其处于最终状态。

何时使用工作进程版本控制

在根本不应该执行未知或不受支持的业务流程版本的情况下,使用工作线程版本控制。 辅助角色版本控制将停止业务流程执行,而不是将版本处理代码置于辅助角色中。 此方法允许更简单的编排代码。 无需进行任何代码更改,即可处理各种部署方案,例如蓝绿部署。

后续步骤