Definir e consultar o status de orquestração personalizada

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

  • Relatar o progresso no meio do voo – permitir que uma interface do usuário mostre qual etapa uma orquestração atingiu sem esperar que ela seja concluída.
  • Retornar dados dinâmicos aos chamadores — exibir recomendações, informações de desconto ou instruções para a próxima etapa enquanto a orquestração ainda está em execução.
  • Coordenar com sistemas externos – compartilhe o estado para que outros serviços ou operadores humanos possam consultar e agir.

Aviso

A carga de status personalizada é limitada a 16 KB de texto JSON UTF-16. Se você precisar de uma carga útil maior, utilize o armazenamento externo e armazene uma referência (como um URL de blob) no estado personalizado.

Em Azure Functions, esse status está disponível por meio da API GetStatus HTTP ou SDK API equivalente no objeto cliente de orquestração.

Em SDKs de Tarefa Durável, esse status está disponível por meio de APIs de consulta de status de orquestração no DurableTaskClient (por exemplo, GetInstanceAsync em .NET ou getInstanceMetadata em Java).

Importante

Atualmente, o SDK da Tarefa Durável do PowerShell não está disponível.

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

A tabela a seguir resume padrões comuns. Selecione um caso de uso para ir para o exemplo correspondente.

Caso de uso Descrição
Visualizar o progresso da orquestração Atualize uma cadeia de caracteres ou objeto após cada atividade para que os clientes possam exibir um indicador de progresso.
Retornar metadados dinâmicos aos clientes Defina dados estruturados (como recomendações) que os clientes renderizam sem precisar de pontos de extremidade personalizados do lado do servidor.
Fornecer dados acionáveis aos clientes Apresente URLs de agendamento, detalhes sobre o desconto ou instruções da próxima etapa para os quais os clientes tomam medidas enquanto o processo de orquestração aguarda um evento externo.
Consultar o status personalizado Leia o valor de status personalizado de um cliente usando APIs HTTP ou chamadas do SDK.

Visualizar o progresso da orquestração

Nesse padrão, o orquestrador chama SetCustomStatus (ou o equivalente em seu idioma) depois que cada atividade é concluída, atualizando o status com o nome da última cidade completada. Um cliente consulta o endpoint de status, lê o estado atual e atualiza um indicador de progresso na IU.

O exemplo a seguir demonstra como compartilhar progresso usando o endpoint de status HTTP das Durable Functions:

Observação

Esses 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 as 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 a seguir demonstra o compartilhamento de progresso usando as APIs de cliente do SDK de Tarefa Durável:

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 sondar metadados de orquestração e aguardar até que o CustomStatus campo seja definido como "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 código do cliente a seguir monitora o status de orquestração e aguarda até que CustomStatus seja configurado para "London" antes de retornar 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;
  }
}

Retornar metadados dinâmicos aos clientes

Você pode usar o status de orquestração personalizado para retornar dados estruturados, como recomendações personalizadas, para clientes sem criar endpoints separados. O orquestrador define o status personalizado com base na entrada e o cliente o lê por meio da API de status padrão. Isso mantém o código do lado do cliente genérico enquanto toda a lógica permanece no 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

Nesse padrão, o orquestrador exibe informações sensíveis ao tempo — como um desconto, uma URL de reserva e um tempo limite — por meio do status personalizado e, em seguida, pausa para aguardar um evento externo. Um cliente lê o status personalizado para exibir a oferta e envia o evento de confirmação de volta ao orquestrador quando o usuário age.

[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 status da orquestração personalizada

Os exemplos anteriores mostram como definir o status personalizado do código do orquestrador. Esta seção se concentra em como os clientes externos leem esse valor.

Depois que um orquestrador chama SetCustomStatus, os clientes externos podem consultar o valor por meio da API HTTP Durable Functions interna. Por exemplo:

GET /runtime/webhooks/durabletask/instances/instance123

A resposta inclui o customStatus campo junto com metadados de runtime:

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

Você também pode consultar o status personalizado programaticamente usando o SDK do cliente de orquestração. Para obter uma referência completa, consulte instâncias de consulta.

Os SDKs de Tarefas Duráveis não fornecem um ponto de extremidade de status HTTP integrado. Em vez disso, consulta programaticamente o estado personalizado usando APIs de metadados da instância de orquestração no DurableTaskClient.

using Microsoft.DurableTask.Client;

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

Aviso

A carga de status personalizada é limitada a 16 KB de texto JSON UTF-16.

Próximas Etapas