Définir et interroger l’état de l’orchestration personnalisée

L’état de l’orchestration personnalisée vous permet d’attacher des métadonnées JSON arbitraires à une instance d’orchestration en cours d’exécution afin que les clients externes puissent l’interroger à tout moment. Utilisez l’état personnalisé lorsque vous devez :

  • Signaler la progression en cours : permettez à une interface utilisateur de montrer à quelle étape une orchestration est parvenue sans attendre sa finalisation.
  • Retournez des données dynamiques aux appelants : recommandations de surface, informations de remise ou instructions à l’étape suivante pendant l’exécution de l’orchestration.
  • Coordonnez avec des systèmes externes : partagez l’état sur lequel d’autres services ou opérateurs humains peuvent interroger et agir.

Avertissement

La charge utile de statut personnalisé est limitée à 16 Ko de texte JSON UTF-16. Si vous avez besoin d'une charge utile plus importante, commencez par utiliser un stockage externe, puis stockez une référence (comme une URL de blob) dans l'état personnalisé.

Dans Azure Functions, cet état est disponible via l’API HTTP GetStatus ou l’API SDK équivalente sur l’objet client d’orchestration.

Dans les SDK Durable Task, cet état est disponible via les API de requête du statut d’orchestration sur le DurableTaskClient (par exemple, GetInstanceAsync en .NET ou getInstanceMetadata en Java).

Important

Actuellement, le Kit de développement logiciel (SDK) PowerShell Durable Task n’est pas disponible.

Exemples de cas d’usage pour l’état d’orchestration personnalisé

Le tableau suivant récapitule les modèles courants. Sélectionnez un cas d’usage pour accéder à l’exemple correspondant.

Cas d’utilisation Description
Visualiser la progression de l’orchestration Mettez à jour une chaîne ou un objet après chaque activité afin que les clients puissent afficher un indicateur de progression.
Retourner des métadonnées dynamiques aux clients Définissez des données structurées (comme des recommandations) que les clients affichent sans avoir besoin de points de terminaison côté serveur personnalisés.
Fournir des données actionnables aux clients Mettre en évidence les URL de réservation, les informations de remise ou les instructions sur les prochaines étapes que les clients suivent pendant que l’orchestration attend un événement externe.
Interroger l’état personnalisé Lisez la valeur d’état personnalisée d’un client à l’aide d’API HTTP ou d’appels sdk.

Visualiser la progression de l’orchestration

Dans ce modèle, l’orchestrateur appelle SetCustomStatus (ou l’équivalent dans votre langue) après l'achèvement de chaque activité, mettant à jour le statut avec le nom de la dernière ville terminée. Un client interroge le point de terminaison d’état, lit la valeur actuelle et met à jour un indicateur de progression dans l’interface utilisateur.

L’exemple suivant illustre le partage de progression à l’aide du point de terminaison d'état HTTP de Durable Functions.

Note

Ces exemples sont écrits pour Durable Functions 2.x et ne sont pas compatibles avec Durable Functions 1.x. Pour plus d’informations sur les différences entre les versions, consultez l’article 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}!";
}

L’exemple suivant illustre le partage de progression à l’aide des API clientes du Kit de développement logiciel (SDK) 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;
    }
}

Le client peut interroger les métadonnées d’orchestration et attendre que le CustomStatus champ soit défini sur "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;
}

Le code client suivant interroge l’état de l’orchestration et attend que CustomStatus soit défini sur "London" avant de retourner une réponse :

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

Retourner des métadonnées dynamiques aux clients

Vous pouvez utiliser l’état d’orchestration personnalisé pour retourner des données structurées, comme des recommandations personnalisées, aux clients sans créer de points de terminaison distincts. L’orchestrateur définit l’état personnalisé en fonction de l’entrée et le client le lit via l’API d’état standard. Cela conserve le code côté client générique alors que toute la logique reste côté serveur.

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

Fournir des données actionnables aux clients

Dans ce modèle, l’orchestrateur met en évidence des informations sensibles au temps( comme une remise, une URL de réservation et un délai d’expiration) via un état personnalisé, puis s’interrompt pour attendre un événement externe. Un client lit l’état personnalisé pour afficher l’offre et renvoie l’événement de confirmation à l’orchestrateur lorsque l’utilisateur agit.

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

Interroger l’état de l’orchestration personnalisée

Les exemples précédents montrent comment définir l’état personnalisé à partir du code d’orchestrateur. Cette section se concentre sur la façon dont les clients externes lisent cette valeur.

Une fois qu’un orchestrateur appelle SetCustomStatus, les clients externes peuvent interroger la valeur via l’API HTTP intégrée Durable Functions. Par exemple:

GET /runtime/webhooks/durabletask/instances/instance123

La réponse inclut le customStatus champ en même temps que les métadonnées du 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"
}

Vous pouvez également interroger l’état personnalisé par programmation à l’aide du Kit de développement logiciel (SDK) du client d’orchestration. Pour obtenir une référence complète, consultez instances de requête.

Les SDK Durable Task ne fournissent pas d'endpoint d’état HTTP intégré. Au lieu de cela, interrogez l’état personnalisé de manière programmatique à l’aide des API de métadonnées d’instance d’orchestration sur le DurableTaskClient.

using Microsoft.DurableTask.Client;

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

Avertissement

La charge utile de statut personnalisé est limitée à 16 Ko de texte JSON UTF-16.

Étapes suivantes