Establecimiento y consulta del estado de orquestación personalizada

El estado de orquestación personalizada permite adjuntar metadatos JSON arbitrarios a una instancia de orquestación en ejecución para que los clientes externos puedan consultarlos en cualquier momento. Use el estado personalizado cuando necesite:

  • Informe de progreso a mitad de vuelo : permita que una interfaz de usuario muestre qué paso ha alcanzado una orquestación sin esperar a que se complete.
  • Devolver datos dinámicos a los solicitantes: mostrar recomendaciones, información sobre descuentos o instrucciones para el siguiente paso mientras la orquestación sigue en ejecución.
  • Coordinar con sistemas externos — comparta un estado que otros servicios u operadores humanos puedan sondear y sobre el cual puedan actuar.

Advertencia

La carga de estado personalizada está limitada a 16 KB de texto JSON UTF-16. Si necesita una carga mayor, use almacenamiento externo y almacene una referencia (por ejemplo, una dirección URL de blob) en el estado personalizado en su lugar.

En Azure Functions, este estado está disponible a través de la API HTTP GetStatus o la API del SDK equivalente en el objeto cliente de orquestación.

En los SDK de Durable Task, este estado está disponible a través de las API de consulta de estado de orquestación en la DurableTaskClient (por ejemplo, GetInstanceAsync en .NET o getInstanceMetadata en Java).

Importante

Actualmente, el SDK de Durable Task de PowerShell no está disponible.

Ejemplos de casos de uso del estado de orquestación personalizado

En la tabla siguiente se resumen los patrones comunes. Seleccione un caso de uso para ir al ejemplo correspondiente.

Caso de uso Descripción
Visualización del progreso de la orquestación Actualice una cadena o un objeto después de cada actividad para que los clientes puedan mostrar un indicador de progreso.
Devolver metadatos dinámicos a los clientes Establezca datos estructurados (como recomendaciones) que los clientes representen sin necesidad de puntos de conexión personalizados del lado servidor.
Proporcionar datos accionables a los clientes Mostrar URL de reserva, información sobre descuentos o instrucciones para el siguiente paso que los clientes pueden seguir mientras la orquestación espera un evento externo.
Consulta del estado personalizado Lea el valor de estado personalizado de un cliente mediante las API HTTP o las llamadas del SDK.

Visualización del progreso de la orquestación

En este patrón, el orquestador llama a SetCustomStatus (o su equivalente en su idioma) una vez que se completa cada actividad, actualizando el estado con el nombre de la última ciudad completada. Un cliente sondea el punto de conexión de estado, lee el valor actual y actualiza un indicador de progreso en la interfaz de usuario.

El siguiente ejemplo muestra cómo compartir el progreso mediante el punto de conexión de estado HTTP de Durable Functions:

Nota:

Estos ejemplos se escriben para Durable Functions 2.x y no son compatibles con Durable Functions 1.x. Para más información sobre las diferencias entre versiones, consulte el artículo Versiones de 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}!";
}

En el ejemplo siguiente se muestra la compartición del progreso mediante las APIs cliente del SDK de Durable Task.

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

El cliente puede sondear los metadatos de orquestación y esperar hasta que el CustomStatus campo esté establecido en "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;
}

El código de cliente siguiente sondea el estado de orquestación y espera hasta que CustomStatus se establezca en "London" antes de devolver una respuesta.

[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 metadatos dinámicos a los clientes

Puede usar el estado de orquestación personalizado para devolver datos estructurados (como recomendaciones personalizadas) a los clientes sin crear puntos de conexión independientes. El orquestador establece el estado personalizado en función de la entrada y el cliente lo lee a través de la API de estado estándar. Esto mantiene el código del lado cliente genérico mientras toda la lógica permanece en el lado 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);
    }
}

Proporcionar datos accionables a los clientes

En este patrón, el orquestador presenta información sujeta a tiempo – como un descuento, una URL de reserva y un tiempo de espera – a través de un estado personalizado, luego hace una pausa para esperar un evento externo. Un cliente lee el estado personalizado para mostrar la oferta y devuelve el evento de confirmación al orquestador cuando el usuario actúa.

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

Consulta del estado de orquestación personalizada

En los ejemplos anteriores se muestra cómo establecer el estado personalizado a partir del código del orquestador. Esta sección se centra en cómo los clientes externos leen ese valor.

Después de que un orquestador llame a SetCustomStatus, los clientes externos pueden consultar el valor a través de la API HTTP integrada de Durable Functions. Por ejemplo:

GET /runtime/webhooks/durabletask/instances/instance123

La respuesta incluye el campo customStatus junto con los metadatos de tiempo de ejecución.

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

También puede consultar el estado personalizado de forma programática usando el SDK del cliente de orquestación. Para obtener una referencia completa, consulte Instancias de consulta.

Los SDK de Durable Task no proporcionan un punto de conexión de estado HTTP integrado. En su lugar, consulte el estado personalizado mediante programación utilizando las API de metadatos de la instancia de orquestación en el DurableTaskClient.

using Microsoft.DurableTask.Client;

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

Advertencia

La carga de estado personalizada está limitada a 16 KB de texto JSON UTF-16.

Pasos siguientes