Les orchestrateurs singleton dans Durable Task

Pour les travaux en arrière-plan, vous devez souvent vous assurer qu'une seule instance d'un orchestrateur particulier s'exécute à la fois, empêchant l'exécution simultanée des orchestrations dupliquées. Vous pouvez implémenter ce modèle singleton dans Durable Functions ou les kits SDK Durable Task en affectant un ID d’instance spécifique à un orchestrateur lors de sa création, puis vérifier si une instance avec cet ID est déjà en cours d’exécution avant de commencer un nouvel ID.

Cet article explique comment implémenter des orchestrateurs singleton avec des exemples de code pour chaque langage pris en charge.

Prerequisites

Note

Il existe une condition de course potentielle dans le modèle singleton. Si deux clients exécutent simultanément la logique de vérification et de démarrage, les deux appels peuvent signaler la réussite, mais une seule instance d’orchestration démarre réellement. Selon vos besoins, cela peut avoir des effets secondaires indésirables. Si des garanties à instance unique strictes sont requises, envisagez d’ajouter des mécanismes de verrouillage supplémentaires.

Important

Actuellement, le Kit de développement logiciel (SDK) PowerShell Durable Task n’est pas disponible.

Exemple d’orchestrateur Singleton

L’exemple suivant montre une fonction déclenchée par HTTP qui crée une orchestration de tâche en arrière-plan singleton. Le code tente de s’assurer qu’une seule instance active existe pour un ID d’instance spécifié.

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

Note

Le code C# précédent concerne le modèle worker isolé, qui est le modèle recommandé pour les applications .NET. Pour plus d’informations sur les différences entre les modèles de travail en cours et isolés, consultez l’article Versions de Durable Functions.

L’exemple suivant montre comment créer une orchestration singleton à l’aide des kits SDK Durable Task. Le code tente de s’assurer qu’une seule instance active existe pour un ID d’instance spécifié.

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

Fonctionnement du modèle singleton

Étant donné que les ID d’instance sont uniques dans un hub de tâches, la planification d’une orchestration avec un ID fixe connu et la vérification de son état empêche d’abord les exécutions simultanées en double. Par défaut, les ID d’instance sont générés de manière aléatoire. Dans les exemples précédents, toutefois, un ID d’instance spécifique est transmis. Le code récupère ensuite les métadonnées de l’instance d’orchestration pour vérifier si une instance avec cet ID est déjà en cours d’exécution. Si aucune instance de ce type n’est en cours d’exécution, une nouvelle instance est créée avec cet ID.

La fonction d’orchestrateur elle-même peut utiliser n’importe quel modèle , une fonction standard qui démarre et se termine, ou une orchestration éternelle qui s’exécute en continu. Le modèle singleton contrôle uniquement le nombre d’instances exécutées simultanément.

Étapes suivantes