Definir e consultar o estado de orquestração personalizado

O estado de orquestração personalizado permite-lhe anexar metadados JSON arbitrários a uma instância de orquestração em execução para que clientes externos possam consultá-la a qualquer momento. Use o estado personalizado quando precisar:

  • Reporte o progresso a meio do voo — deixe que uma interface mostre a que etapa a orquestração atingiu, sem esperar que esta seja concluída.
  • Devolva dados dinâmicos aos utilizadores — apresentar recomendações, informações de desconto ou instruções de próximo passo enquanto a orquestração ainda está em execução.
  • Coordenar com sistemas externos — partilhar o estado que outros serviços ou operadores humanos possam consultar e agir.

Advertência

A carga útil de estado personalizado está limitada a 16 KB de texto JSON UTF-16. Se precisares de uma carga útil maior, usa armazenamento externo e guarda uma referência (como um URL de blob) no estado personalizado.

Em Funções do Azure, este estado está disponível através da API GetStatus HTTP ou da API equivalente SDK no objeto cliente de orquestração.

Nos SDKs de Tarefas Duráveis, este estado está disponível através de APIs de consulta de estado de orquestração no DurableTaskClient (por exemplo, GetInstanceAsync em .NET ou getInstanceMetadata em Java).

Importante

Atualmente, o PowerShell Durable Task SDK não está disponível.

Exemplos de casos de uso para estado personalizado de orquestração

A tabela seguinte resume padrões comuns. Selecione um caso de uso para saltar para o exemplo correspondente.

Caso de utilização Description
Visualize o progresso da orquestração Atualize uma cadeia ou objeto após cada atividade para que os clientes possam mostrar um indicador de progresso.
Devolver metadados dinâmicos aos clientes Define dados estruturados (como recomendações) que os clientes renderizam sem precisarem de endpoints personalizados do lado do servidor.
Fornecer dados acionáveis aos clientes URLs de reservas no Surface, informações de desconto ou instruções para os passos seguintes que os clientes seguem enquanto a orquestração aguarda um evento externo.
Consultar estado personalizado Leia o valor de estado personalizado de um cliente usando APIs HTTP ou chamadas SDK.

Visualize o progresso da orquestração

Neste padrão, o orquestrador chama SetCustomStatus (ou o equivalente na sua língua) após cada atividade concluída, atualizando o estado com o nome da última cidade concluída. Um cliente consulta o endpoint de estado, lê o valor atual e atualiza um indicador de progresso na interface.

O exemplo seguinte demonstra a partilha de progresso usando o endpoint de estado HTTP das Durable Functions:

Observação

Estes exemplos são escritos para Durable Functions 2.x e não são compatíveis com Durable Functions 1.x. Para obter mais informações sobre as diferenças entre versões, consulte o artigo Durable Functions versions .

[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}!";
}

O exemplo seguinte demonstra a partilha de progresso usando as APIs do cliente Durable Task SDK:

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;
    }
}

O cliente pode consultar metadados de orquestração e esperar até que o CustomStatus campo esteja definido para "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;
}

O seguinte código cliente interroga o estado da orquestração e espera até CustomStatus ser definido para "London" antes de devolver uma resposta:

[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;
  }
}

Devolver metadados dinâmicos aos clientes

Pode usar o estado de orquestração personalizado para devolver dados estruturados — como recomendações personalizadas — aos clientes sem construir endpoints separados. O orquestrador define o estado personalizado com base na entrada, e o cliente lê-o através da API de estado padrão. Isto mantém o código do lado do cliente genérico enquanto toda a lógica permanece do lado do servidor.

[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);
    }
}

Fornecer dados acionáveis aos clientes

Neste padrão, o orquestrador revela informações sensíveis ao tempo — como um desconto, uma URL de reserva e um timeout — através do estado personalizado, e depois pausa para esperar por um evento externo. Um cliente lê o estado personalizado para mostrar a oferta e envia o evento de confirmação de volta ao orquestrador quando o utilizador atua.

[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;
    }
}

Consultar o estado da orquestração personalizada

Os exemplos anteriores mostram como definir o estado personalizado a partir do código do Orchestrator. Esta secção foca-se em como os clientes externos interpretam esse valor.

Depois de um orquestrador chamar SetCustomStatus, clientes externos podem consultar o valor através da API HTTP Durable Functions incorporada. Por exemplo:

GET /runtime/webhooks/durabletask/instances/instance123

A resposta inclui o customStatus campo juntamente com metadados de execução:

{
  "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"
}

Também pode consultar estados personalizados de forma programática usando o SDK do cliente de orquestração. Para uma referência completa, consulte Consultar instâncias.

Os SDKs de Tarefas Duráveis não fornecem um endpoint HTTP de estado incorporado. Em vez disso, consulte o estado personalizado programaticamente usando APIs de metadados de instância de orquestração no DurableTaskClient.

using Microsoft.DurableTask.Client;

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

Advertência

A carga útil de estado personalizado está limitada a 16 KB de texto JSON UTF-16.

Passos seguintes