Orkiestratory jednotonowe w trwałym zadaniu

W przypadku zadań w tle często trzeba upewnić się, że tylko jedno wystąpienie określonego orkiestratora jest uruchamiane jednocześnie, uniemożliwiając jednoczesne uruchamianie zduplikowanych aranżacji. Ten pojedynczy wzorzec można zaimplementować w Durable Functions lub Durable Task SDK przypisując określony identyfikator wystąpienia do orkiestratora podczas jego tworzenia, a następnie sprawdzając, czy wystąpienie z tym identyfikatorem jest już uruchomione przed uruchomieniem nowego.

W tym artykule pokazano, jak zaimplementować pojedyncze orkiestratory z przykładami kodu dla każdego obsługiwanego języka.

Wymagania wstępne

Uwaga / Notatka

Istnieje potencjalny stan wyścigu we wzorze singleton. Jeśli dwóch klientów wykonuje logikę weryfikacji i uruchomienia jednocześnie, oba wywołania mogą zakończyć się powodzeniem, ale faktycznie uruchamia się tylko jedno wystąpienie orkiestracji. W zależności od wymagań może to mieć niepożądane skutki uboczne. Jeśli wymagane są ścisłe gwarancje dotyczące pojedynczej instancji, rozważ dodanie dodatkowych mechanizmów blokowania.

Ważna

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

Przykład orkiestratora pojedynczego

W poniższym przykładzie przedstawiono funkcję wyzwalacza HTTP, która tworzy pojedynczą aranżację zadań w tle. Kod próbuje upewnić się, że istnieje tylko jedno aktywne wystąpienie dla określonego identyfikatora wystąpienia.

[Function("HttpStartSingle")]
public static async Task<HttpResponseData> RunSingle(
    [HttpTrigger(AuthorizationLevel.Function, "post", Route = "orchestrators/{functionName}/{instanceId}")] HttpRequestData req,
    [DurableClient] DurableTaskClient starter,
    string functionName,
    string instanceId,
    FunctionContext executionContext)
{
    ILogger logger = executionContext.GetLogger("HttpStartSingle");

    // Check if an instance with the specified ID already exists or an existing one stopped running(completed/failed/terminated).
    OrchestrationMetadata? existingInstance = await starter.GetInstanceAsync(instanceId, getInputsAndOutputs: false);
    if (existingInstance == null 
    || existingInstance.RuntimeStatus == OrchestrationRuntimeStatus.Completed 
    || existingInstance.RuntimeStatus == OrchestrationRuntimeStatus.Failed 
    || existingInstance.RuntimeStatus == OrchestrationRuntimeStatus.Terminated)
    {
        // An instance with the specified ID doesn't exist or an existing one stopped running, create one.
        string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
        await starter.ScheduleNewOrchestrationInstanceAsync(functionName, requestBody, new StartOrchestrationOptions { InstanceId = instanceId });
        logger.LogInformation($"Started orchestration with ID = '{instanceId}'.");
        return await starter.CreateCheckStatusResponseAsync(req, instanceId);
    }
    else
    {
        // An instance with the specified ID exists or an existing one still running, don't create one.
        var response = req.CreateResponse(HttpStatusCode.Conflict);
        await response.WriteStringAsync($"An instance with ID '{instanceId}' already exists.");
        return response;
    }
}

Uwaga / Notatka

Poprzedni kod języka C# jest przeznaczony dla izolowanego modelu roboczego, który jest zalecanym modelem dla aplikacji .NET. Aby uzyskać więcej informacji na temat różnic między modelami roboczymi zintegrowanymi i izolowanymi, zobacz artykuł wersje Durable Functions.

W poniższym przykładzie pokazano, jak utworzyć singletonową orkiestrację przy użyciu Durable Task SDK. Kod próbuje upewnić się, że istnieje tylko jedno aktywne wystąpienie dla określonego identyfikatora wystąpienia.

using Microsoft.DurableTask.Client;

// Check if an instance with the specified ID already exists
string instanceId = "singleton-job";
OrchestrationMetadata? existingInstance = await client.GetInstanceAsync(instanceId, getInputsAndOutputs: false);

if (existingInstance == null ||
    existingInstance.RuntimeStatus == OrchestrationRuntimeStatus.Completed ||
    existingInstance.RuntimeStatus == OrchestrationRuntimeStatus.Failed ||
    existingInstance.RuntimeStatus == OrchestrationRuntimeStatus.Terminated)
{
    // An instance with the specified ID doesn't exist or an existing one stopped running, create one.
    await client.ScheduleNewOrchestrationInstanceAsync("MyOrchestration", input, new StartOrchestrationOptions(instanceId));
    Console.WriteLine($"Started orchestration with ID = '{instanceId}'.");
}
else
{
    // An instance with the specified ID exists or an existing one still running.
    Console.WriteLine($"An instance with ID '{instanceId}' already exists.");
}

Jak działa wzorzec projektowy singleton

Ponieważ identyfikatory wystąpień są unikatowe w centrum zadań, planowanie aranżacji ze znanym, stałym identyfikatorem i sprawdzaniem jego stanu najpierw zapobiega duplikowaniu współbieżnych uruchomień. Domyślnie identyfikatory wystąpień to losowo generowane identyfikatory GUID. Jednak w poprzednich przykładach jest przekazywany określony identyfikator wystąpienia. Następnie kod pobiera metadane instancji orkiestracji, aby sprawdzić, czy instancja z tym identyfikatorem jest już uruchomiona. Jeśli takie wystąpienie nie jest uruchomione, nowe wystąpienie z tym identyfikatorem zostanie utworzone.

Funkcja orkiestratora może używać dowolnego wzorca — standardowa funkcja, która się rozpoczyna i kończy, lub wieczna orkiestracja, która działa w sposób ciągły. Wzorzec pojedynczy steruje tylko tym, ile wystąpień jest uruchamianych współbieżnie.

Następne kroki