Singleton-Orchestratoren in dauerhafter Aufgabe

Bei Hintergrundaufträgen müssen Sie häufig sicherstellen, dass jeweils nur eine Instanz eines bestimmten Orchestrators ausgeführt wird, um zu verhindern, dass doppelte Orchestrierungen gleichzeitig ausgeführt werden. Sie können dieses Singletonmuster in Durable Functions oder im Durable Task SDKs implementieren, indem Sie einem Orchestrator beim Erstellen eine bestimmte Instanz-ID zuweisen und dann überprüfen, ob eine Instanz mit dieser ID bereits ausgeführt wird, bevor Sie eine neue Instanz starten.

In diesem Artikel wird gezeigt, wie Singleton-Orchestratoren mit Codebeispielen für jede unterstützte Sprache implementiert werden.

Voraussetzungen

Hinweis

Es gibt eine potenzielle Wettlaufbedingung im Singleton-Muster. Wenn zwei Clients die Check-and-Start-Logik gleichzeitig ausführen, melden beide Aufrufe möglicherweise Erfolg, aber nur eine Orchestrierungsinstanz wird tatsächlich gestartet. Je nach Ihren Anforderungen kann dies unerwünschte Nebenwirkungen haben. Wenn strenge Einzelinstanzgarantien erforderlich sind, sollten Sie zusätzliche Sperrmechanismen hinzufügen.

Von Bedeutung

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

Beispiel eines Singleton-Orchestrators

Im folgenden Beispiel wird eine HTTP-Triggerfunktion veranschaulicht, mit der eine Orchestrierung für einen Singleton-Hintergrundauftrag erstellt wird. Der Code versucht sicherzustellen, dass nur eine aktive Instanz für eine angegebene Instanz-ID vorhanden ist.

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

Hinweis

Der vorherige C#-Code ist für das isolierte Workermodell vorgesehen, das das empfohlene Modell für .NET-Apps ist. Weitere Informationen zu den Unterschieden zwischen den In-Process- und isolierten Worker-Modellen finden Sie im Artikel Durable Functions-Versionen.

Das folgende Beispiel zeigt, wie Sie eine Singleton-Orchestrierung mit den SdKs für dauerhafte Aufgaben erstellen. Der Code versucht sicherzustellen, dass nur eine aktive Instanz für eine angegebene Instanz-ID vorhanden ist.

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.");
}

Funktionsweise des Singletonmusters

Da Instanz-IDs innerhalb eines Aufgabenhubs eindeutig sind, verhindert das Planen einer Orchestrierung mit einer bekannten, festen ID und das anschließende Überprüfen ihres Status doppelte gleichzeitige Ausführungen. Standardmäßig werden Instanz-IDs als zufällig generierte GUIDs erstellt. In den vorherigen Beispielen wird jedoch eine bestimmte Instanz-ID übergeben. Der Code ruft dann die Orchestrierungsinstanzmetadaten ab, um zu überprüfen, ob eine Instanz mit dieser ID bereits ausgeführt wird. Wenn keine solche Instanz ausgeführt wird, wird eine neue Instanz mit dieser ID erstellt.

Die Orchestratorfunktion selbst kann jedes Muster verwenden – eine Standardfunktion, die gestartet und abgeschlossen wird, oder eine ewige Orchestrierung , die kontinuierlich ausgeführt wird. Das Singletonmuster steuert nur, wie viele Instanzen gleichzeitig ausgeführt werden.

Nächste Schritte