Freigeben über


Benutzerdefinierter Orchestrierungsstatus

Mit dem benutzerdefinierten Orchestrierungsstatus können Sie einen benutzerdefinierten Statuswert für eine Orchestrierungsinstanz festlegen. Externe Clients können diesen Wert abfragen, um den Fortschritt nachzuverfolgen oder Metadaten zu teilen, während die Orchestrierung ausgeführt wird.

In Azure Functions ist dieser Status über die HTTP GetStatus-API oder die entsprechende SDK-API für das Orchestrierungsclientobjekt verfügbar.

In dauerhaften Task-SDKs ist dieser Status über die API zur Abfrage des Orchestrierungsstatus im DurableTaskClient verfügbar (z. B. GetInstanceAsync in .NET oder getInstanceMetadata in Java).

Von Bedeutung

Derzeit ist das PowerShell Durable Task SDK nicht verfügbar.

Beispiele für Anwendungsfälle

Visualisieren des Fortschritts

Clients können den Statusendpunkt abfragen und eine Fortschrittsanzeige darstellen, die den aktuellen Ausführungsstand visualisiert. Das folgende Beispiel zeigt, wie Fortschritte geteilt werden können:

Hinweis

Diese Beispiele werden für Durable Functions 2.x geschrieben und sind nicht mit Durable Functions 1.x kompatibel. Weitere Informationen zu den Unterschieden zwischen den Versionen finden Sie im Artikel 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}!";
}

Clients können Orchestrierungsmetadaten abrufen und eine Fortschrittsanzeige anzeigen, welche die aktuelle Ausführungsphase visualisiert. Das folgende Beispiel zeigt, wie Fortschritte geteilt werden können:

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

Der Client kann Orchestrierungsmetadaten abfragen und warten, bis das CustomStatus Feld auf folgendes "London"festgelegt ist:

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

Und dann erhält der Client die Ausgabe der Orchestrierung nur, wenn das CustomStatus-Feld auf "London" festgelegt ist:

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

Ausgabeanpassung

Sie können den Benutzerdefinierten Orchestrierungsstatus verwenden, um Benutzer zu segmentieren, indem Sie eine angepasste Ausgabe basierend auf eindeutigen Merkmalen oder Interaktionen zurückgeben. Bei benutzerdefiniertem Orchestrierungsstatus bleibt ihr clientseitiger Code generisch, während alle wichtigsten Änderungen auf der Serverseite erfolgen:

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

Anweisungsspezifikation

Ihr Orchestrator kann kundenspezifische Anweisungen über den benutzerdefinierten Status bereitstellen. Die benutzerdefinierten Statusanweisungen entsprechen den Schritten im Orchestrierungscode:

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

Abfragen des benutzerdefinierten Status

Das folgende Beispiel zeigt, wie benutzerdefinierte Statuswerte mithilfe der integrierten HTTP-APIs abgefragt werden können.

public static async Task SetStatusTest([OrchestrationTrigger] IDurableOrchestrationContext context)
{
    // ...do work...

    // update the status of the orchestration with some arbitrary data
    var customStatus = new { nextActions = new [] {"A", "B", "C"}, foo = 2, };
    context.SetCustomStatus(customStatus);

    // ...do more work...
}

Während der Ausführung der Orchestrierung können externe Clients diesen benutzerdefinierten Status abrufen:

GET /runtime/webhooks/durabletask/instances/instance123

Clients erhalten die folgende Antwort:

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

Warnung

Die benutzerdefinierte Statusnutzlast ist auf 16 KB UTF-16 JSON-Text beschränkt. Wenn Sie eine größere Nutzlast benötigen, empfiehlt es sich, externen Speicher zu verwenden.

Dauerhafte Aufgaben-SDKs stellen keinen integrierten HTTP-Statusendpunkt bereit. Stattdessen fragen Sie den angepassten Status über die Metadaten-APIs der Orchestrierung-Instanz auf der DurableTaskClient ab.

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

public class MyCustomStatusOrchestrator : TaskOrchestrator<object?, object?>
{
    public override Task<object?> RunAsync(TaskOrchestrationContext context, object? input)
    {
        context.SetCustomStatus(new { nextActions = new[] { "A", "B", "C" }, foo = 2 });
        return Task.FromResult<object?>(null);
    }
}

Fragen Sie den benutzerdefinierten Status von einem Client ab:

using Microsoft.DurableTask.Client;

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

Warnung

Die benutzerdefinierte Statusnutzlast ist auf 16 KB UTF-16 JSON-Text beschränkt.

Nächste Schritte