Singleton orchestrators i Durable Task

För bakgrundsjobb måste du ofta se till att endast en instans av en viss orkestrerare körs i taget, vilket förhindrar att flera orkestreringar körs samtidigt. Du kan implementera det här singleton-mönstret i Durable Functions eller Durable Task SDK:er genom att tilldela ett specifikt instans-ID till en orkestrerare när du skapar det och sedan kontrollera om en instans med det ID:t redan körs innan du startar en ny.

Den här artikeln visar hur du implementerar singleton orchestrators med kodexempel för varje språk som stöds.

Prerequisites

Anmärkning

Det finns en potentiell gängkonflikt i singleton-mönstret. Om två klienter kör check-and-start-logiken samtidigt kan båda anropen rapportera framgång, men bara en orkestreringsinstans startar faktiskt. Beroende på dina krav kan detta ha oönskade biverkningar. Om det krävs strikta garantier för en enskild instans kan du överväga att lägga till ytterligare låsningsmekanismer.

Viktigt!

PowerShell Durable Task SDK är för närvarande inte tillgängligt.

Singleton Orchestrator-exempel

I följande exempel visas en HTTP-utlösarfunktion som skapar en singleton-bakgrundsjobborkestrering. Koden försöker se till att endast en aktiv instans finns för ett angivet instans-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;
    }
}

Anmärkning

Den tidigare C#-koden är för den isolerade arbetsmodellen, som är den rekommenderade modellen för .NET appar. Mer information om skillnaderna mellan de processbaserade och isolerade arbetsmodellerna finns i artikeln Durable Functions versioner.

I följande exempel visas hur du skapar en singleton-orkestrering med hjälp av Durable Task SDK:er. Koden försöker se till att endast en aktiv instans finns för ett angivet instans-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.");
}

Så här fungerar singleton-mönstret

Eftersom ett instans-ID är unikt i en aktivitetshubb, förhindrar duplikatsamtidiga körningar genom att först schemalägga en orkestrering med ett känt, fast ID och verifiera dess status. Som förval är instans-ID:n slumpmässigt genererade GUID:er. I föregående exempel skickas dock ett specifikt instans-ID. Koden hämtar sedan metadata för orkestreringsinstansen för att kontrollera om en instans med det ID:t redan körs. Om ingen sådan instans körs skapas en ny instans med det ID:t.

Själva orkestreringsfunktionen kan använda valfritt mönster – en standardfunktion som startar och slutförs, eller en evig orkestrering som körs kontinuerligt. Singleton-mönstret styr bara hur många instanser som körs samtidigt.

Nästa steg