Zarządzanie wystąpieniami orkiestracji

Wbudowane interfejsy API zarządzania wystąpieniami umożliwiają uruchamianie, wykonywanie zapytań, kończenie, wstrzymywanie, wznawianie i przeczyszczanie wystąpień aranżacji w trwałych przepływach pracy. W Durable Functions powiązanie klienta orchestration uwidacznia te interfejsy API. W zestawach SDK Durable Task te same operacje są dostępne przez klasę DurableTaskClient. W tym artykule pokazano, jak wykonać każdą operację zarządzania wystąpieniami przy użyciu przykładów kodu dla obu platform.

Wskazówka

Azure Durable Task Scheduler jest zalecanym zapleczem technicznym zarówno dla Durable Functions, jak i Durable Task SDKs, zapewniając w pełni zarządzane, bezserwerowe środowisko do uruchamiania odpornych przepływów pracy w dużej skali.

Uruchamianie wystąpień

Metoda start-new (lub schedule-new) na kliencie orkiestracji uruchamia nowe wystąpienie orkiestracji. Wewnętrznie ta metoda zapisuje wiadomość do skonfigurowanego backendu (takiego jak Durable Task Scheduler), a następnie zwraca wiadomość. Ten komunikat asynchronicznie wyzwala początek aranżacji o określonej nazwie.

Poniżej przedstawiono parametry uruchamiania nowego wystąpienia orkiestracji:

Parameter Opis
Nazwa Nazwa orchestratora służy do harmonogramu.
Dane wejściowe Wszelkie dane serializowalne w JSON, które powinny być przekazywane jako wejście do funkcji orchestratora.
Identyfikator wystąpienia (Opcjonalnie) Unikalny identyfikator instancji. Jeśli nie określisz tego parametru, metoda używa losowego identyfikatora.

Wskazówka

Użyj identyfikatora losowego dla identyfikatora wystąpienia, jeśli jest to możliwe. Identyfikatory wystąpień losowych pomagają zapewnić równomierny rozkład obciążenia podczas skalowania funkcji orkiestratora na wielu maszynach wirtualnych. Odpowiedni czas używania niestosowych identyfikatorów wystąpień jest wtedy, gdy identyfikator pochodzi ze źródła zewnętrznego lub podczas implementowania wzorca orkiestratora typu singleton.

Parameter Opis
Nazwa Nazwa orkiestracji do harmonogramu.
Dane wejściowe Wszelkie dane serializowalne w JSON, które powinny być przekazywane jako wejście do orkiestracji.
Identyfikator wystąpienia (Opcjonalnie) Unikalny identyfikator instancji. Jeśli nie określisz tego parametru, metoda używa losowego identyfikatora.

Wskazówka

Użyj identyfikatora losowego dla identyfikatora wystąpienia, jeśli jest to możliwe. Identyfikatory wystąpień losowych pomagają zapewnić równomierne rozłożenie obciążenia podczas skalowania orkiestracji na wielu maszynach wirtualnych. Odpowiedni czas używania niestosowych identyfikatorów wystąpień jest wtedy, gdy identyfikator pochodzi ze źródła zewnętrznego lub podczas implementowania wzorca orkiestratora typu singleton.

Przykładowa funkcja, którą za chwilę zobaczysz, uruchamia nową instancję orkiestracji.

Model izolowanego pracownika
[Function("HelloWorldQueueTrigger")]
public static async Task Run(
    [QueueTrigger("start-queue")] string input,
    [DurableClient] DurableTaskClient client,
    FunctionContext functionContext)
{
    string instanceId = await client.ScheduleNewOrchestrationInstanceAsync("HelloWorld", input);
    functionContext.GetLogger("HelloWorldQueueTrigger")
        .LogInformation("Started orchestration with ID = '{InstanceId}'.", instanceId);
}

Model w trakcie przetwarzania
[FunctionName("HelloWorldQueueTrigger")]
public static async Task Run(
    [QueueTrigger("start-queue")] string input,
    [DurableClient] IDurableOrchestrationClient starter,
    ILogger log)
{
    string instanceId = await starter.StartNewAsync("HelloWorld", input);
    log.LogInformation($"Started orchestration with ID = '{instanceId}'.");
}

Ważna

Obecnie zestaw POWERShell Durable Task SDK nie jest dostępny.

Poniższy kod pokazuje, jak uruchomić nowe wystąpienie orkiestracji przy użyciu SDK Durable Task:

using Microsoft.DurableTask.Client;

// Schedule a new orchestration instance
string instanceId = await client.ScheduleNewOrchestrationInstanceAsync("HelloWorld", input);
Console.WriteLine($"Started orchestration with ID = '{instanceId}'.");

// Optionally, wait for the orchestration to start
OrchestrationMetadata metadata = await client.WaitForInstanceStartAsync(instanceId, timeout: TimeSpan.FromSeconds(30));

Instancje zapytań

Po uruchomieniu nowych wystąpień orkiestracji najprawdopodobniej musisz wykonać zapytanie dotyczące ich stanu czasu wykonywania, aby dowiedzieć się, czy są uruchomione, ukończone lub zakończone niepowodzeniem.

Metoda get-status na kliencie orkiestracji zwraca stan instancji orkiestracji.

Przyjmuje ( instanceId wymagane), showHistory (opcjonalne), showHistoryOutput (opcjonalne) i showInput (opcjonalnie) jako parametry.

  • showHistory: Jeśli ustawiono wartość true, odpowiedź zawiera historię wykonywania.
  • showHistoryOutput: Jeśli ustawiono wartość true, historia wykonywania zawiera dane wyjściowe działań.
  • showInput: Jeśli ustawiono wartość false, odpowiedź nie zawiera danych wejściowych funkcji. Domyślna wartość to true.

Metoda zwraca obiekt o następujących właściwościach:

Property Opis
Nazwa Nazwa funkcji orkiestratora.
Identyfikator wystąpienia ID instancji orkiestracji (powinno być takie samo jak instanceId wejście).
Czas utworzenia Moment, w którym funkcja orchestratora zaczyna działać.
LastUpdatedTime Czas, w którym orkiestracja się kończy, to punkt kontrolny.
Dane wejściowe Dane wejściowe funkcji jako wartość JSON. To pole nie jest wypełniane, jeśli showInput ma wartość false.
CustomStatus Status niestandardowej orkiestracji w formacie JSON.
Output Dane wyjściowe funkcji jako wartość JSON (jeśli działanie funkcji zostanie zakończone). Jeśli funkcja orkiestratora zakończy się niepowodzeniem, ta właściwość zawiera szczegóły błędu. Jeśli funkcja orkiestratora jest zawieszona lub zakończona, ta właściwość zawiera przyczynę zawieszenia lub zakończenia (jeśli istnieje).
RuntimeStatus: Oczekuje Instancja została zaplanowana, ale jeszcze nie została uruchomiona.
RuntimeStatus: Działający Instancja działa.
RuntimeStatus: Ukończone Instancja zakończyła się normalnie.
Stan uruchomienia: Kontynuowano jako nowe Instancja uruchomiła się ponownie z nową historią. Ten stan jest stanem przejściowym.
RuntimeStatus: Nieudane Instancja zakończyła się błędem.
RuntimeStatus: Zakończony Instancja nagle się zatrzymała.
RuntimeStatus: Zawieszony Instancja zostaje zawieszona i można ją wznowić później.
Historia Historia wykonania orkiestracji. To pole jest wypełniane tylko wtedy, gdy showHistory jest ustawione na true.
Parameter Opis
showHistory Jeśli ustawimy na true, odpowiedź zawiera historię wykonania.
showHistoryOutput Jeśli ustawiono wartość true, historia wykonywania zawiera dane wyjściowe działania.
showInput Jeśli ustawiono na false, odpowiedź nie zawiera danych wejściowych orkiestracji. Domyślna wartość to true.

Metoda zwraca obiekt o następujących właściwościach:

Property Opis
Nazwa Nazwa orkiestracji.
Identyfikator wystąpienia Identyfikator instancji orkiestracji (powinien być taki sam jak dane wejściowe instanceId).
Czas utworzenia Moment, w którym orkiestracja zaczyna działać.
LastUpdatedTime Czas, w którym orkiestracja się kończy, to punkt kontrolny.
Dane wejściowe Dane wejściowe orkiestracji jako wartość JSON. To pole nie jest wypełniane, jeśli showInput ma wartość false.
CustomStatus Status niestandardowej orkiestracji w formacie JSON.
Output Dane wyjściowe orkiestracji jako wartość JSON (jeśli orkiestracja się zakończy). Jeśli aranżacja zakończy się niepowodzeniem, ta właściwość zawiera szczegóły błędu. Jeśli aranżacja jest zawieszona lub zakończona, ta właściwość zawiera przyczynę zawieszenia lub zakończenia (jeśli istnieje).
RuntimeStatus: Oczekuje Instancja została zaplanowana, ale jeszcze nie została uruchomiona.
RuntimeStatus: Działający Instancja jest uruchomiona.
RuntimeStatus: Ukończone Instancja zakończyła się normalnie.
Stan uruchomienia: Kontynuowano jako nowe Instancja uruchomiła się ponownie z nową historią. Ten stan jest stanem przejściowym.
RuntimeStatus: Nieudane Instancja zakończyła się błędem.
RuntimeStatus: Zakończony Instancja nagle się zatrzymała.
RuntimeStatus: Zawieszony Instancja zostaje zawieszona i może zostać wznowiona w późniejszym czasie.
Historia Historia wykonania orkiestracji. To pole jest wypełniane tylko wtedy, gdy showHistory jest ustawione na true.

Uwaga / Notatka

Orkiestrator nie jest oznaczany jako Completed dopóki nie zakończą się wszystkie zaplanowane zadania i nie powróci orkiestrator. Innymi słowy, nie wystarczy, aby orkiestrator dotarł do swojej return instrukcji, aby został oznaczony jako Completed. Jest to szczególnie istotne w przypadkach, w których WhenAny jest używane; te orkiestratory często return przed wykonaniem wszystkich zaplanowanych zadań.

Ta metoda zwraca null (.NET i Java), undefined (JavaScript) lub None (Python), jeśli instancja nie istnieje.

Model izolowanego pracownika
[Function("GetStatus")]
public static async Task Run(
    [DurableClient] DurableTaskClient client,
    [QueueTrigger("check-status-queue")] string instanceId)
{
    OrchestrationMetadata? metadata = await client.GetInstanceAsync(
        instanceId,
        getInputsAndOutputs: true);
    // Do something based on the current status.
}

Model w trakcie przetwarzania
[FunctionName("GetStatus")]
public static async Task Run(
    [DurableClient] IDurableOrchestrationClient client,
    [QueueTrigger("check-status-queue")] string instanceId)
{
    DurableOrchestrationStatus status = await client.GetStatusAsync(instanceId);
    // do something based on the current status.
}

using Microsoft.DurableTask.Client;

// Get the status of an orchestration instance
OrchestrationMetadata? metadata = await client.GetInstanceAsync(instanceId, getInputsAndOutputs: true);
if (metadata != null)
{
    OrchestrationRuntimeStatus status = metadata.RuntimeStatus;
    // do something based on the current status
}

Wykonywanie zapytań dotyczących wszystkich wystąpień orkiestracji

Możesz używać interfejsów API w SDK w danym języku, aby wykonywać zapytania dotyczące statusów wszystkich instancji orkiestracji w centrum zadań. Interfejs API "list-instances" lub "get-status" zwraca listę obiektów reprezentujących instancje orkiestracji zgodne z parametrami zapytania.

Model izolowanego pracownika
[Function("GetAllStatus")]
public static async Task Run(
    [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post")] HttpRequestData request,
    [DurableClient] DurableTaskClient client,
    FunctionContext functionContext)
{
    ILogger logger = functionContext.GetLogger("GetAllStatus");
    AsyncPageable<OrchestrationMetadata> instances = client.GetAllInstancesAsync(
        new OrchestrationQuery());

    await foreach (OrchestrationMetadata instance in instances)
    {
        logger.LogInformation("{Instance}", instance);
    }
}

Model w trakcie przetwarzania
[FunctionName("GetAllStatus")]
public static async Task Run(
    [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post")] HttpRequestMessage req,
    [DurableClient] IDurableOrchestrationClient client,
    ILogger log)
{
    var noFilter = new OrchestrationStatusQueryCondition();
    OrchestrationStatusQueryResult result = await client.ListInstancesAsync(
        noFilter,
        CancellationToken.None);
    foreach (DurableOrchestrationStatus instance in result.DurableOrchestrationState)
    {
        log.LogInformation(JsonConvert.SerializeObject(instance));
    }

    // Note: ListInstancesAsync only returns the first page of results.
    // To request additional pages provide the result.ContinuationToken
    // to the OrchestrationStatusQueryCondition's ContinuationToken property.
}

using Microsoft.DurableTask.Client;

// Query all orchestration instances
AsyncPageable<OrchestrationMetadata> instances = client.GetAllInstancesAsync(new OrchestrationQuery());

await foreach (OrchestrationMetadata instance in instances)
{
    Console.WriteLine(instance.InstanceId);
}

Instancje orkiestracji zapytań z filtrami

Co zrobić, jeśli nie potrzebujesz wszystkich informacji, które udostępnia zapytanie wystąpienia standardowego? Na przykład co zrobić, jeśli szukasz czasu utworzenia orkiestracji lub statusu działania orkiestracji? Zawęź zapytanie, stosując filtry.

Model izolowanego pracownika
[Function("QueryStatus")]
public static async Task Run(
    [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post")] HttpRequestData request,
    [DurableClient] DurableTaskClient client,
    FunctionContext functionContext)
{
    ILogger logger = functionContext.GetLogger("QueryStatus");
    var query = new OrchestrationQuery
    {
        Statuses = new[]
        {
            OrchestrationRuntimeStatus.Pending,
            OrchestrationRuntimeStatus.Running,
        },
        CreatedFrom = DateTime.UtcNow.Subtract(TimeSpan.FromDays(7)),
        CreatedTo = DateTime.UtcNow.Subtract(TimeSpan.FromDays(1)),
        PageSize = 100,
    };

    await foreach (OrchestrationMetadata instance in client.GetAllInstancesAsync(query))
    {
        logger.LogInformation("{Instance}", instance);
    }
}

Model w trakcie przetwarzania
[FunctionName("QueryStatus")]
public static async Task Run(
    [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post")] HttpRequestMessage req,
    [DurableClient] IDurableOrchestrationClient client,
    ILogger log)
{
    // Get the first 100 running or pending instances that were created between 7 and 1 days ago
    var queryFilter = new OrchestrationStatusQueryCondition
    {
        RuntimeStatus = new[]
        {
            OrchestrationRuntimeStatus.Pending,
            OrchestrationRuntimeStatus.Running,
        },
        CreatedTimeFrom = DateTime.UtcNow.Subtract(TimeSpan.FromDays(7)),
        CreatedTimeTo = DateTime.UtcNow.Subtract(TimeSpan.FromDays(1)),
        PageSize = 100,
    };

    OrchestrationStatusQueryResult result = await client.ListInstancesAsync(
        queryFilter,
        CancellationToken.None);
    foreach (DurableOrchestrationStatus instance in result.DurableOrchestrationState)
    {
        log.LogInformation(JsonConvert.SerializeObject(instance));
    }
}

using Microsoft.DurableTask.Client;

// Get running or pending instances created in the last 7 days
var query = new OrchestrationQuery
{
    Statuses = new[] { OrchestrationRuntimeStatus.Running, OrchestrationRuntimeStatus.Pending },
    CreatedFrom = DateTime.UtcNow.AddDays(-7),
    CreatedTo = DateTime.UtcNow.AddDays(-1),
    PageSize = 100
};

AsyncPageable<OrchestrationMetadata> instances = client.GetAllInstancesAsync(query);

await foreach (OrchestrationMetadata instance in instances)
{
    Console.WriteLine($"{instance.InstanceId}: {instance.RuntimeStatus}");
}

Kończenie instancji orkiestracji

Jeśli masz wystąpienie orkiestracji, które trwa zbyt długo, lub musisz zatrzymać je przed ukończeniem z jakiegokolwiek powodu, możesz go zakończyć.

API do zakończenia ma dwa parametry: identyfikator wystąpienia i ciąg znaków przyczyny, które są zapisywane w dziennikach i w stanie wystąpienia.

Model izolowanego pracownika
[Function("TerminateInstance")]
public static Task Run(
    [DurableClient] DurableTaskClient client,
    [QueueTrigger("terminate-queue")] string instanceId)
{
    string reason = "Found a bug";
    return client.TerminateInstanceAsync(instanceId, reason);
}

Model w trakcie przetwarzania
[FunctionName("TerminateInstance")]
public static Task Run(
    [DurableClient] IDurableOrchestrationClient client,
    [QueueTrigger("terminate-queue")] string instanceId)
{
    string reason = "Found a bug";
    return client.TerminateAsync(instanceId, reason);
}

using Microsoft.DurableTask.Client;

string reason = "Found a bug";
await client.TerminateInstanceAsync(instanceId, reason);

Zakończone wystąpienie ostatecznie przechodzi do stanu Terminated. Ale to przejście nie dzieje się natychmiast. Zamiast tego operacja zakończenia jest kolejkowana w centrum zadań wraz z innymi operacjami dla tego wystąpienia. Możesz użyć interfejsów API zapytania instancji, aby dowiedzieć się, kiedy zakończona instancja faktycznie osiągnęła Terminated stan.

Uwaga / Notatka

Zakończenie wystąpienia nie jest obecnie propagowane. Funkcje aktywności i pod-orkiestracje działają do zakończenia, niezależnie od tego, czy kończy się wystąpienie orkiestracji, które je wywołało.

Wstrzymywanie i wznawianie procesów orkiestracji

Wstrzymanie orkiestracji umożliwia zatrzymanie działającej orkiestracji. W przeciwieństwie do zakończenia orkiestracji, można wznowić zawieszonego orkiestratora w późniejszym czasie.

Dwa parametry API zawieszenia to identyfikator wystąpienia i ciąg przyczyny, które są zapisywane w dziennikach i w stanie wystąpienia.

Model izolowanego pracownika
[Function("SuspendResumeInstance")]
public static async Task Run(
    [DurableClient] DurableTaskClient client,
    [QueueTrigger("suspend-resume-queue")] string instanceId)
{
    // To suspend an orchestration
    string suspendReason = "Need to pause workflow";
    await client.SuspendInstanceAsync(instanceId, suspendReason);

    // To resume an orchestration
    string resumeReason = "Continue workflow";
    await client.ResumeInstanceAsync(instanceId, resumeReason);
}

Model w trakcie przetwarzania
[FunctionName("SuspendResumeInstance")]
public static async Task Run(
    [DurableClient] IDurableOrchestrationClient client,
    [QueueTrigger("suspend-resume-queue")] string instanceId)
{
    // To suspend an orchestration
    string suspendReason = "Need to pause workflow";
    await client.SuspendAsync(instanceId, suspendReason);

    // To resume an orchestration
    string resumeReason = "Continue workflow";
    await client.ResumeAsync(instanceId, resumeReason);
}

using Microsoft.DurableTask.Client;

// To suspend an orchestration
string suspendReason = "Need to pause workflow";
await client.SuspendInstanceAsync(instanceId, suspendReason);

// To resume an orchestration
string resumeReason = "Continue workflow";
await client.ResumeInstanceAsync(instanceId, resumeReason);

Wstrzymane wystąpienie ostatecznie przechodzi do stanu Suspended. Jednak to przejście nie następuje natychmiast. Zamiast tego, operacja wstrzymania jest kolejkowana w hubie zadań wraz z innymi operacjami dla tego wystąpienia. Użyj API zapytań dla wystąpień, aby dowiedzieć się, kiedy działające wystąpienie rzeczywiście osiągnęło Suspended stan.

Po wznowieniu zawieszonego koordynatora jego stan zmieni się z powrotem na Running.

Wyślij zdarzenia do wystąpień

W niektórych scenariuszach funkcje orkiestratora muszą czekać i nasłuchiwać zdarzeń zewnętrznych. Przykłady, w których takie podejście jest przydatne, obejmują scenariusze monitorowania i interakcji człowieka .

W niektórych scenariuszach orkiestracje muszą oczekiwać i nasłuchiwać na zdarzenia zewnętrzne. Przykłady, w których takie podejście jest przydatne, obejmują scenariusze monitorowania i interakcji człowieka .

Powiadomienia o zdarzeniach można wysyłać do uruchomionych wystąpień przy użyciu interfejsu API zgłaszania zdarzeń klienta orkiestracji. Orkiestracje mogą nasłuchiwać tych zdarzeń i reagować na nie przy użyciu interfejsu API oczekiwania na zdarzenie zewnętrzne orkiestratora.

Parametry wywołania zdarzenia to:

  • Identyfikator wystąpienia: unikatowy identyfikator wystąpienia.
  • Nazwa zdarzenia: nazwa zdarzenia do wysłania.
  • Dane zdarzenia: ładunek z możliwością serializacji JSON do wysłania do wystąpienia.
Model izolowanego pracownika
[Function("RaiseEvent")]
public static Task Run(
    [DurableClient] DurableTaskClient client,
    [QueueTrigger("event-queue")] string instanceId)
{
    int[] eventData = new int[] { 1, 2, 3 };
    return client.RaiseEventAsync(instanceId, "MyEvent", eventData);
}

Model w trakcie przetwarzania
[FunctionName("RaiseEvent")]
public static Task Run(
    [DurableClient] IDurableOrchestrationClient client,
    [QueueTrigger("event-queue")] string instanceId)
{
    int[] eventData = new int[] { 1, 2, 3 };
    return client.RaiseEventAsync(instanceId, "MyEvent", eventData);
}

using Microsoft.DurableTask.Client;

int[] eventData = new int[] { 1, 2, 3 };
await client.RaiseEventAsync(instanceId, "MyEvent", eventData);

Uwaga / Notatka

Jeśli nie ma wystąpienia orkiestracji z określonym identyfikatorem wystąpienia, komunikat zdarzenia zostanie odrzucony. Jeśli instancja istnieje, ale nie oczekuje jeszcze na zdarzenie, zdarzenie jest przechowywane w stanie instancji, aż będzie gotowe do odebrania i przetworzenia.

Poczekaj na ukończenie aranżacji

W długotrwałych orkiestracjach możesz chcieć poczekać i uzyskać wyniki orkiestracji. W takich przypadkach warto również zdefiniować limit czasu orkiestracji. Jeśli przekroczono limit czasu, stan aranżacji jest zwracany zamiast wyników.

Użyj interfejsu API "czekaj na ukończenie lub utwórz odpowiedź do sprawdzenia stanu", aby uzyskać rzeczywisty wynik z wystąpienia orkiestracji synchronicznie. Domyślnie ta metoda ma limit czasu wynoszący dziesięć sekund i interwał sondowania wynoszący jedną sekundę.

Oto przykładowa funkcja wyzwalacza HTTP, która pokazuje, jak używać tego interfejsu API:

Model izolowanego pracownika
[Function("HttpSyncStart")]
public static async Task<HttpResponseData> Run(
    [HttpTrigger(
        AuthorizationLevel.Function,
        "post",
        Route = "orchestrators/{functionName}/wait")] HttpRequestData request,
    [DurableClient] DurableTaskClient client,
    string functionName)
{
    string instanceId = await client.ScheduleNewOrchestrationInstanceAsync(functionName);

    using var timeoutCancellation = new CancellationTokenSource(TimeSpan.FromSeconds(30));
    return await client.WaitForCompletionOrCreateCheckStatusResponseAsync(
        request,
        instanceId,
        timeoutCancellation.Token);
}

Model w trakcie przetwarzania
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT License. See LICENSE in the project root for license information.

using System;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.DurableTask;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.Extensions.Logging;

namespace VSSample
{
    public static class HttpSyncStart
    {
        private const string Timeout = "timeout";
        private const string RetryInterval = "retryInterval";

        [FunctionName("HttpSyncStart")]
        public static async Task<HttpResponseMessage> Run(
            [HttpTrigger(AuthorizationLevel.Function, methods: "post", Route = "orchestrators/{functionName}/wait")]
            HttpRequestMessage req,
            [DurableClient] IDurableOrchestrationClient starter,
            string functionName,
            ILogger log)
        {
            // Function input comes from the request content.
            object eventData = await req.Content.ReadAsAsync<object>();
            string instanceId = await starter.StartNewAsync(functionName, eventData);

            log.LogInformation($"Started orchestration with ID = '{instanceId}'.");

            TimeSpan timeout = GetTimeSpan(req, Timeout) ?? TimeSpan.FromSeconds(30);
            TimeSpan retryInterval = GetTimeSpan(req, RetryInterval) ?? TimeSpan.FromSeconds(1);
            
            return await starter.WaitForCompletionOrCreateCheckStatusResponseAsync(
                req,
                instanceId,
                timeout,
                retryInterval);
        }

        private static TimeSpan? GetTimeSpan(HttpRequestMessage request, string queryParameterName)
        {
            string queryParameterStringValue = request.RequestUri.ParseQueryString()[queryParameterName];
            if (string.IsNullOrEmpty(queryParameterStringValue))
            {
                return null;
            }

            return TimeSpan.FromSeconds(double.Parse(queryParameterStringValue));
        }
    }
}

SDK Durable Task zapewniają metodę oczekiwania na zakończenie orkiestracji w sposób synchroniczny.

using Microsoft.DurableTask.Client;

// Wait for orchestration to complete with a timeout
OrchestrationMetadata metadata = await client.WaitForInstanceCompletionAsync(
    instanceId,
    timeout: TimeSpan.FromSeconds(30),
    getInputsAndOutputs: true);

if (metadata.RuntimeStatus == OrchestrationRuntimeStatus.Completed)
{
    Console.WriteLine($"Output: {metadata.SerializedOutput}");
}

Wywołaj funkcję za pomocą następującego wiersza. Użyj dwóch sekund dla limitu czasu i 0,5 sekundy dla interwału ponawiania prób:

curl -X POST "http://localhost:7071/orchestrators/E1_HelloSequence/wait?timeout=2&retryInterval=0.5"

Uwaga / Notatka

Powyższe polecenie cURL zakłada, że masz funkcję orkiestratora o nazwie E1_HelloSequence w projekcie. Ze względu na sposób zapisywania funkcji wyzwalacza HTTP można zastąpić ją nazwą dowolnej funkcji orkiestratora w projekcie.

W zależności od czasu wymaganego do uzyskania odpowiedzi z wystąpienia orkiestracji istnieją dwa przypadki:

  • Wystąpienia orkiestracji kończą się w zdefiniowanym limicie czasu (w tym przypadku dwie sekundy), a odpowiedź jest rzeczywistym wyjściem wystąpienia orkiestracji, dostarczanym synchronicznie:
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Date: Thu, 14 Dec 2021 06:14:29 GMT
Transfer-Encoding: chunked

[
    "Hello Tokyo!",
    "Hello Seattle!",
    "Hello London!"
]
HTTP/1.1 202 Accepted
Content-Type: application/json; charset=utf-8
Date: Thu, 14 Dec 2021 06:13:51 GMT
Location: http://localhost:7071/runtime/webhooks/durabletask/instances/d3b72dddefce4e758d92f4d411567177?taskHub={taskHub}&connection={connection}&code={systemKey}
Retry-After: 10
Transfer-Encoding: chunked

{
    "id": "d3b72dddefce4e758d92f4d411567177",
    "sendEventPostUri": "http://localhost:7071/runtime/webhooks/durabletask/instances/d3b72dddefce4e758d92f4d411567177/raiseEvent/{eventName}?taskHub={taskHub}&connection={connection}&code={systemKey}",
    "statusQueryGetUri": "http://localhost:7071/runtime/webhooks/durabletask/instances/d3b72dddefce4e758d92f4d411567177?taskHub={taskHub}&connection={connection}&code={systemKey}",
    "terminatePostUri": "http://localhost:7071/runtime/webhooks/durabletask/instances/d3b72dddefce4e758d92f4d411567177/terminate?reason={text}&taskHub={taskHub}&connection={connection}&code={systemKey}",
    "suspendPostUri": "http://localhost:7071/runtime/webhooks/durabletask/instances/d3b72dddefce4e758d92f4d411567177/suspend?reason={text}&taskHub={taskHub}&connection={connection}&code={systemKey}",
    "resumePostUri": "http://localhost:7071/runtime/webhooks/durabletask/instances/d3b72dddefce4e758d92f4d411567177/resume?reason={text}&taskHub={taskHub}&connection={connection}&code={systemKey}"
}

Uwaga / Notatka

Format adresów URL elementu webhook może się różnić w zależności od wersji uruchomionego hosta Azure Functions. Powyższy przykład dotyczy hosta Azure Functions 3.0.

Pobieranie adresów URL webhooków zarządzania za pomocą HTTP dla wystąpień orkiestracji

Użyj systemu zewnętrznego do monitorowania lub zgłaszania zdarzeń do orkiestracji. Systemy zewnętrzne komunikują się z Durable Functions za pośrednictwem adresów URL webhooków, które są częścią domyślnej odpowiedzi opisanej w Odnajdywaniu adresów URL interfejsu API HTTP. Adresy URL elementów webhook są również dostępne programistycznie przy użyciu powiązania klienta orkiestracji. W szczególności interfejs API tworzenia ładunku zarządzania protokołem HTTP pobiera obiekt z możliwością serializacji zawierający te adresy URL elementów webhook.

Interfejs API tworzenia ładunku zarządzania http ma jeden parametr:

  • Identyfikator wystąpienia: unikatowy identyfikator wystąpienia.

Metody zwracają obiekt z następującymi właściwościami ciągu:

  • Identyfikator: identyfikator wystąpienia orkiestracji (powinien być taki sam jak InstanceId wejście).
  • StatusQueryGetUri: URL stanu wystąpienia orkiestracji.
  • SendEventPostUri: adres URL "zgłoś zdarzenie" wystąpienia orkiestracji.
  • TerminatePostUri: adres URL "terminate" wystąpienia orkiestracji.
  • PurgeHistoryDeleteUri: adres URL "czyszczenia historii" wystąpienia orkiestracji.
  • SuspendPostUri: adres URL "suspend" wystąpienia orkiestracji.
  • ResumePostUri: URL "resume" dla wystąpienia orkiestracji.

Funkcje wysyłają wystąpienia tych obiektów do systemów zewnętrznych w celu monitorowania lub zgłaszania zdarzeń w odpowiednich orkiestracjach, jak pokazano w poniższych przykładach.

Model izolowanego pracownika
[Function("SendInstanceInfo")]
[CosmosDBOutput(
    databaseName: "MonitorDB",
    containerName: "HttpManagementPayloads",
    Connection = "CosmosDBConnectionSetting")]
public static object SendInstanceInfo(
    [ActivityTrigger] TaskActivityContext context,
    [DurableClient] DurableTaskClient client)
{
    HttpManagementPayload payload = client.CreateHttpManagementPayload(context.InstanceId);

    // Send the payload to Azure Cosmos DB.
    return new { Payload = payload, id = context.InstanceId };
}

Model w trakcie przetwarzania
[FunctionName("SendInstanceInfo")]
public static void SendInstanceInfo(
    [ActivityTrigger] IDurableActivityContext ctx,
    [DurableClient] IDurableOrchestrationClient client,
    [CosmosDB(
        databaseName: "MonitorDB",
        containerName: "HttpManagementPayloads",
        Connection = "CosmosDBConnectionSetting")]out dynamic document)
{
    HttpManagementPayload payload = client.CreateHttpManagementPayload(ctx.InstanceId);

    // send the payload to Azure Cosmos DB
    document = new { Payload = payload, id = ctx.InstanceId };
}

Ponowne przewijanie wystąpień aranżacji

Jeśli wystąpi błąd orkiestracji z nieoczekiwanego powodu, cofnij wystąpienie do poprzedniego, zdrowego stanu przy użyciu interfejsu API utworzonego w tym celu.

Uwaga / Notatka

Ten interfejs API nie jest przeznaczony do zastąpienia odpowiednich zasad obsługi błędów i ponawiania prób. Zamiast tego ma być używany tylko w przypadkach, gdy wystąpienia orkiestracji kończą się niepowodzeniem z nieoczekiwanych powodów. Orkiestracje w stanach innych niż Failed (na przykład Running, Pending, Terminated lub Completed) nie mogą być "cofnięte". Aby uzyskać więcej informacji na temat obsługi błędów i zasad ponawiania prób, zobacz artykuł Obsługa błędów .

Użyj metody RewindAsync (.NET) lub rewind (JavaScript) w powiązaniu klienta orkiestracji, aby przywrócić orkiestrację do stanu Running. Ta metoda ponownie uruchamia również błędy wykonywania działań lub podorchestracji, które spowodowały niepowodzenie aranżacji.

Załóżmy, że masz przepływ pracy obejmujący serię zatwierdzeń przez ludzi. Załóżmy, że szereg funkcji aktywności powiadamia kogoś, że ich zatwierdzenie jest potrzebne i czekają na odpowiedź w czasie rzeczywistym. Po otrzymaniu odpowiedzi lub przekroczeniu limitu czasu na wszystkie działania zatwierdzania, załóżmy, że inne działanie kończy się niepowodzeniem z powodu błędnej konfiguracji aplikacji, na przykład z powodu nieprawidłowego ciągu połączenia bazy danych. Wynikiem jest niepowodzenie aranżacji głęboko w przepływie pracy. Za pomocą interfejsu API RewindAsync (.NET) lub rewind (JavaScript) administrator aplikacji może naprawić błąd konfiguracji i przewinąć nieudaną aranżację z powrotem do stanu bezpośrednio przed awarią. Żaden z kroków interakcji z człowiekiem nie musi zostać ponownie zatwierdzony, a aranżacja może zakończyć się pomyślnie.

Uwaga / Notatka

Funkcja przewijania nie obsługuje instancji orkiestracji korzystających z trwałych czasomierzy.

Model izolowanego pracownika
[Function("RewindInstance")]
public static Task Run(
    [DurableClient] DurableTaskClient client,
    [QueueTrigger("rewind-queue")] string instanceId)
{
    string reason = "Orchestrator failed and needs to be revived.";
    return client.RewindInstanceAsync(instanceId, reason);
}

Model w trakcie przetwarzania
[FunctionName("RewindInstance")]
public static Task Run(
    [DurableClient] IDurableOrchestrationClient client,
    [QueueTrigger("rewind-queue")] string instanceId)
{
    string reason = "Orchestrator failed and needs to be revived.";
    return client.RewindAsync(instanceId, reason);
}

using Microsoft.DurableTask.Client;

string reason = "Orchestrator failed and needs to be revived.";
await client.RewindInstanceAsync(instanceId, reason);

Ponowne uruchamianie wystąpień orkiestracji

Ponowne uruchomienie orkiestracji powoduje utworzenie nowego wystąpienia przy użyciu historii wcześniej uruchomionego wystąpienia. Ta funkcja jest przydatna, gdy chcesz ponownie uruchomić orkiestrację z tymi samymi danymi wejściowymi i wzorcem identyfikatora wystąpienia, tworząc nowy przebieg bazujący na oryginalnej orkiestracji.

Model izolowanego pracownika
[Function("RestartInstance")]
public static Task<string?> Run(
    [DurableClient] DurableTaskClient client,
    [QueueTrigger("restart-queue")] string instanceId)
{
    return client.RestartAsync(instanceId, restartWithNewInstanceId: true);
}

Model w trakcie przetwarzania
[FunctionName("RestartInstance")]
public static Task Run(
    [DurableClient] IDurableOrchestrationClient client,
    [QueueTrigger("restart-queue")] string instanceId)
{
    return client.RestartAsync(instanceId, restartWithNewInstanceId: true);
}

using Microsoft.DurableTask.Client;

// Restart an orchestration with a new instance ID
string newInstanceId = await client.RestartInstanceAsync(instanceId, restartWithNewInstanceId: true);
Console.WriteLine($"Restarted as new instance: {newInstanceId}");

// Restart an orchestration keeping the same instance ID
await client.RestartInstanceAsync(instanceId, restartWithNewInstanceId: false);

Historia wystąpienia orkiestracji przeczyszczania

Aby usunąć wszystkie dane skojarzone z orkiestracją, usuń historię instancji. Na przykład usuń wszystkie zasoby pamięci masowej skojarzone z ukończonym wystąpieniem. Użyj interfejsu API przeczyszczania wystąpienia zdefiniowanego przez klienta aranżacji.

W poniższym przykładzie pokazano, jak wyczyścić pojedynczą instancję orkiestracji.

Model izolowanego pracownika
[Function("PurgeInstanceHistory")]
public static async Task Run(
    [DurableClient] DurableTaskClient client,
    [QueueTrigger("purge-queue")] string instanceId)
{
    await client.PurgeInstanceAsync(instanceId);
}

Model w trakcie przetwarzania
[FunctionName("PurgeInstanceHistory")]
public static Task Run(
    [DurableClient] IDurableOrchestrationClient client,
    [QueueTrigger("purge-queue")] string instanceId)
{
    return client.PurgeInstanceHistoryAsync(instanceId);
}

using Microsoft.DurableTask.Client;

// Purge a single orchestration instance
PurgeResult result = await client.PurgeInstanceAsync(instanceId);
Console.WriteLine($"Purged {result.PurgedInstanceCount} instance(s).");

W poniższym przykładzie pokazano funkcję wyzwalaną przez czasomierz, która czyści historię wszystkich wystąpień orkiestracji zakończonych po określonym interwale czasu. W takim przypadku usuwa dane dla wszystkich wystąpień ukończonych 30 lub więcej dni temu. Ta przykładowa funkcja jest zaplanowana raz dziennie, o 12:00 CZASU UTC:

Model izolowanego pracownika
[Function("PurgeInstanceHistory")]
public static async Task Run(
    [DurableClient] DurableTaskClient client,
    [TimerTrigger("0 0 12 * * *")] TimerInfo myTimer)
{
    var filter = new PurgeInstancesFilter(
        CreatedFrom: DateTime.MinValue,
        CreatedTo: DateTime.UtcNow.AddDays(-30),
        Statuses: new[] { OrchestrationRuntimeStatus.Completed });

    await client.PurgeAllInstancesAsync(filter);
}

Model w trakcie przetwarzania
[FunctionName("PurgeInstanceHistory")]
public static Task Run(
    [DurableClient] IDurableOrchestrationClient client,
    [TimerTrigger("0 0 12 * * *")] TimerInfo myTimer)
{
    return client.PurgeInstanceHistoryAsync(
        DateTime.MinValue,
        DateTime.UtcNow.AddDays(-30),  
        new List<OrchestrationStatus>
        {
            OrchestrationStatus.Completed
        });
}

using Microsoft.DurableTask.Client;

// Purge completed instances older than 30 days
var filter = new PurgeInstancesFilter(
    CreatedFrom: DateTime.MinValue,
    CreatedTo: DateTime.UtcNow.AddDays(-30),
    Statuses: new[] { OrchestrationRuntimeStatus.Completed });

PurgeResult result = await client.PurgeAllInstancesAsync(filter);
Console.WriteLine($"Purged {result.PurgedInstanceCount} instance(s).");

Uwaga / Notatka

Aby operacja historii przeczyszczania powiodła się, status uruchomieniowy wystąpienia docelowego musi być Zakończony, Przerwany lub Niepowodzenie zakończone.

Następne kroki