Singleton-orchestrators in Durable Task

Voor achtergrondtaken moet u er vaak voor zorgen dat slechts één exemplaar van een bepaalde Orchestrator tegelijk wordt uitgevoerd, waardoor dubbele orkestraties niet gelijktijdig kunnen plaatsvinden. U kunt dit singleton-patroon implementeren in Durable Functions of de Urable Task SDK's door een specifieke exemplaar-id toe te wijzen aan een orchestrator bij het maken en vervolgens te controleren of een exemplaar met die id al wordt uitgevoerd voordat een nieuwe wordt gestart.

In dit artikel wordt beschreven hoe u singleton-orchestrators implementeert met codevoorbeelden voor elke ondersteunde taal.

Prerequisites

Opmerking

Er is een potentiële racevoorwaarde in het singleton-patroon. Als twee clients gelijktijdig de controle- en startlogica uitvoeren, kunnen beide aanroepen een succes melden, maar slechts één orchestrationexemplaar wordt daadwerkelijk gestart. Afhankelijk van uw vereisten kan dit ongewenste bijwerkingen hebben. Als strikte garanties voor één exemplaar vereist zijn, kunt u extra vergrendelingsmechanismen toevoegen.

Belangrijk

Momenteel is de Durable Task SDK van PowerShell niet beschikbaar.

Voorbeeld van Singleton orchestrator

In het volgende voorbeeld ziet u een HTTP-triggerfunctie waarmee een singleton-achtergrondtaakindeling wordt gemaakt. De code probeert ervoor te zorgen dat er slechts één actief exemplaar bestaat voor een opgegeven exemplaar-id.

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

Opmerking

De vorige C#-code is voor het geïsoleerde werkrolmodel. Dit is het aanbevolen model voor .NET-apps. Zie het artikel Durable Functions versies voor meer informatie over de verschillen tussen de in-proces- en geïsoleerde werkrolmodellen.

In het volgende voorbeeld ziet u hoe u een singleton-orchestratie maakt met behulp van de Durable Task SDK's. De code probeert ervoor te zorgen dat er slechts één actief exemplaar bestaat voor een opgegeven exemplaar-id.

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

Hoe het singleton-patroon werkt

Omdat exemplaar-id's uniek zijn binnen een taakhub, zorgt het plannen van een orchestratie met een bekende, vaste id en eerst de status controleren ervoor dat dubbele gelijktijdige uitvoeringen worden voorkomen. Instantie-id's worden standaard willekeurig gegenereerde GUID's. In de vorige voorbeelden wordt echter een specifieke exemplaar-id doorgegeven. De code haalt vervolgens de metagegevens van het orkestratie-exemplaar op om te controleren of een exemplaar met die ID al wordt uitgevoerd. Als er geen dergelijke instantie wordt uitgevoerd, wordt er een nieuwe instantie met die ID gemaakt.

De orchestratorfunctie zelf kan elk patroon gebruiken: een standaardfunctie die wordt gestart en voltooid, of een eeuwige indeling die continu wordt uitgevoerd. Het singleton-patroon bepaalt alleen hoeveel exemplaren gelijktijdig worden uitgevoerd.

Volgende stappen