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

设置和查询自定义编排状态

自定义业务流程状态使你可以将任意 JSON 元数据附加到正在运行的业务流程实例,以便外部客户端随时可以查询它。 需要使用自定义状态时:

  • 报告中途进度 - 让 UI 显示编排已达到的步骤,而无需等待其完成。
  • 将动态数据返回到调用方 - 在业务流程仍在运行时呈现建议、折扣信息或下一步说明。
  • 与外部系统协调 — 共享状态,以便其他服务或人类操作员可以查询和进行操作。

警告

自定义状态有效负载限制为 16 KB 的 UTF-16 JSON 文本。 如果需要更大的有效负载,请改用外部存储并将引用(如 Blob URL)存储在自定义状态中。

在 Azure Functions 中,可以通过业务流程客户端对象的 HTTP GetStatus API 或等效的 SDK API 获取此状态。

在 Durable Task SDK 中,可以通过 DurableTaskClient 上的业务流程状态查询 API(例如,.NET中的 GetInstanceAsync 或 Java 中的 getInstanceMetadata)获取此状态。

重要

目前,PowerShell Durable Task SDK 不可用。

自定义编排状态的示例用例

下表总结了常见模式。 选择一个用例以跳转到相应的示例。

用例 说明
可视化编排进度 在每个活动之后更新字符串或对象,以便客户端可以显示进度指示器。
将动态元数据返回到客户端 设置客户端在不需要自定义服务器端终结点的情况下呈现的结构化数据(如建议)。
向客户端提供可操作数据 向客户展示预订 URL、折扣信息或下一步操作说明,这些信息可供客户在业务流程等待外部事件期间直接使用。
查询自定义状态 使用 HTTP API 或 SDK 调用从客户端读取自定义状态值。

可视化编排进度

在此模式下,业务流程协调程序在每个活动完成后调用 SetCustomStatus(或你所用语言中的等效项),并使用最后完成的城市名称更新状态。 客户端轮询状态终结点、读取当前值,并在 UI 中更新进度指示器。

以下示例演示如何使用 Durable Functions HTTP 状态终结点进行进度共享:

注释

这些示例针对 Durable Functions 2.x 编写,并且与 Durable Functions 1.x 不兼容。 有关版本之间差异的详细信息,请参阅 Durable Functions 版本一文。

[FunctionName("E1_HelloSequence")]
public static async Task<List<string>> Run(
    [OrchestrationTrigger] IDurableOrchestrationContext context)
{
    var outputs = new List<string>();

    outputs.Add(await context.CallActivityAsync<string>("E1_SayHello", "Tokyo"));
    context.SetCustomStatus("Tokyo");
    outputs.Add(await context.CallActivityAsync<string>("E1_SayHello", "Seattle"));
    context.SetCustomStatus("Seattle");
    outputs.Add(await context.CallActivityAsync<string>("E1_SayHello", "London"));
    context.SetCustomStatus("London");

    // returns ["Hello Tokyo!", "Hello Seattle!", "Hello London!"]
    return outputs;
}

[FunctionName("E1_SayHello")]
public static string SayHello([ActivityTrigger] string name)
{
    return $"Hello {name}!";
}

以下示例演示了使用 Durable Task SDK 客户端 API 的进度共享:

using System.Threading.Tasks;
using Microsoft.DurableTask;

public class HelloCities : TaskOrchestrator<object?, string>
{
    public override async Task<string> RunAsync(TaskOrchestrationContext context, object? input)
    {
        string result = "";

        result += await context.CallActivityAsync<string>("SayHello", "Tokyo") + ", ";
        context.SetCustomStatus("Tokyo");

        result += await context.CallActivityAsync<string>("SayHello", "London") + ", ";
        context.SetCustomStatus("London");

        result += await context.CallActivityAsync<string>("SayHello", "Seattle");
        context.SetCustomStatus("Seattle");

        return result;
    }
}

客户端可以轮询业务流程元数据并等待,直到 CustomStatus 字段设置为 "London"

using System.Threading.Tasks;
using Microsoft.DurableTask.Client;

string instanceId = await client.ScheduleNewOrchestrationInstanceAsync("HelloCities");

OrchestrationMetadata metadata = await client.WaitForInstanceStartAsync(instanceId, getInputsAndOutputs: true);
while (metadata.SerializedCustomStatus is null || metadata.ReadCustomStatusAs<string>() != "London")
{
    await Task.Delay(200);
    metadata = await client.GetInstanceAsync(instanceId, getInputsAndOutputs: true) ?? metadata;
}

以下客户端代码轮询业务流程状态并等待,直到 CustomStatus 被设置为 "London" 后,才会返回响应:

[FunctionName("HttpStart")]
public static async Task<HttpResponseMessage> Run(
    [HttpTrigger(AuthorizationLevel.Function, methods: "post", Route = "orchestrators/{functionName}")] HttpRequestMessage req,
    [DurableClient] IDurableOrchestrationClient starter,
    string functionName,
    ILogger log)
{
    // Function input comes from the request content.
    dynamic eventData = await req.Content.ReadAsAsync<object>();
    string instanceId = await starter.StartNewAsync(functionName, (string)eventData);

    log.LogInformation($"Started orchestration with ID = '{instanceId}'.");

    DurableOrchestrationStatus durableOrchestrationStatus = await starter.GetStatusAsync(instanceId);
    while (durableOrchestrationStatus.CustomStatus.ToString() != "London")
    {
        await Task.Delay(200);
        durableOrchestrationStatus = await starter.GetStatusAsync(instanceId);
    }

    HttpResponseMessage httpResponseMessage = new HttpResponseMessage(HttpStatusCode.OK)
    {
        Content = new StringContent(JsonConvert.SerializeObject(durableOrchestrationStatus))
    };

    return httpResponseMessage;
  }
}

将动态元数据返回到客户端

可以使用自定义业务流程状态将结构化数据(如个性化建议)返回到客户端,而无需生成单独的终结点。 业务流程协调程序根据输入设置自定义状态,客户端通过标准状态 API 读取该状态。 这会保留客户端代码泛型,而所有逻辑都保留在服务器端。

[FunctionName("CityRecommender")]
public static void Run(
  [OrchestrationTrigger] IDurableOrchestrationContext context)
{
  int userChoice = context.GetInput<int>();

  switch (userChoice)
  {
    case 1:
    context.SetCustomStatus(new
    {
      recommendedCities = new[] {"Tokyo", "Seattle"},
      recommendedSeasons = new[] {"Spring", "Summer"}
     });
      break;
    case 2:
      context.SetCustomStatus(new
      {
                recommendedCities = new[] {"Seattle", "London"},
        recommendedSeasons = new[] {"Summer"}
      });
        break;
      case 3:
      context.SetCustomStatus(new
      {
                recommendedCities = new[] {"Tokyo", "London"},
        recommendedSeasons = new[] {"Spring", "Summer"}
      });
        break;
  }

  // Wait for user selection and refine the recommendation
}
using System.Threading.Tasks;
using Microsoft.DurableTask;

public class CityRecommender : TaskOrchestrator<int, object?>
{
    public override Task<object?> RunAsync(TaskOrchestrationContext context, int userChoice)
    {
        switch (userChoice)
        {
            case 1:
                context.SetCustomStatus(new
                {
                    recommendedCities = new[] { "Tokyo", "Seattle" },
                    recommendedSeasons = new[] { "Spring", "Summer" },
                });
                break;
            case 2:
                context.SetCustomStatus(new
                {
                    recommendedCities = new[] { "Seattle", "London" },
                    recommendedSeasons = new[] { "Summer" },
                });
                break;
            case 3:
                context.SetCustomStatus(new
                {
                    recommendedCities = new[] { "Tokyo", "London" },
                    recommendedSeasons = new[] { "Spring", "Summer" },
                });
                break;
        }

        // Wait for user selection and refine the recommendation
        return Task.FromResult<object?>(null);
    }
}

向客户端提供可操作数据

在此模式中,业务流程协调程序通过自定义状态显示时间敏感信息(例如折扣、预订 URL 和超时),然后暂停等待外部事件。 客户端读取自定义状态以显示报价,并在用户执行操作时将确认事件发送回协调器。

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

  int discount = await context.CallActivityAsync<int>("CalculateDiscount", userId);

  context.SetCustomStatus(new
  {
    discount = discount,
    discountTimeout = 60,
    bookingUrl = "https://www.myawesomebookingweb.com",
  });

  bool isBookingConfirmed = await context.WaitForExternalEvent<bool>("BookingConfirmed");

  context.SetCustomStatus(isBookingConfirmed
    ? new {message = "Thank you for confirming your booking."}
    : new {message = "The booking was not confirmed on time. Please try again."});

  return isBookingConfirmed;
}
using System.Threading.Tasks;
using Microsoft.DurableTask;

public class ReserveTicket : TaskOrchestrator<string, bool>
{
    public override async Task<bool> RunAsync(TaskOrchestrationContext context, string userId)
    {
        int discount = await context.CallActivityAsync<int>("CalculateDiscount", userId);

        context.SetCustomStatus(new
        {
            discount,
            discountTimeout = 60,
            bookingUrl = "https://www.myawesomebookingweb.com",
        });

        bool isBookingConfirmed = await context.WaitForExternalEvent<bool>("BookingConfirmed");
        context.SetCustomStatus(isBookingConfirmed
            ? new { message = "Thank you for confirming your booking." }
            : new { message = "The booking was not confirmed on time. Please try again." });

        return isBookingConfirmed;
    }
}

查询自定义编排状态

前面的示例演示如何从编排器代码设置自定义状态。 本部分重点介绍外部客户端如何读取该值。

业务流程协调程序调用 SetCustomStatus 后,外部客户端可以通过内置Durable Functions HTTP API 查询值。 例如:

GET /runtime/webhooks/durabletask/instances/instance123

响应包括 customStatus 字段以及运行时元数据:

{
  "runtimeStatus": "Running",
  "input": null,
  "customStatus": { "nextActions": ["A", "B", "C"], "foo": 2 },
  "output": null,
  "createdTime": "2019-10-06T18:30:24Z",
  "lastUpdatedTime": "2019-10-06T19:40:30Z"
}

还可以使用业务流程客户端 SDK 以编程方式查询自定义状态。 有关完整参考,请参阅 查询实例

持久任务 SDK 不提供内置的 HTTP 状态终结点。 相反,通过 DurableTaskClient 上的业务流程实例元数据 API 以编程方式查询自定义状态。

using Microsoft.DurableTask.Client;

OrchestrationMetadata? metadata = await client.GetInstanceAsync(instanceId, getInputsAndOutputs: true);
string? customStatusJson = metadata?.SerializedCustomStatus;

警告

自定义状态有效负载限制为 16 KB 的 UTF-16 JSON 文本。

后续步骤