Agenti di orchestrazione singleton in Attività durevoli

Per i processi in background, spesso è necessario assicurarsi che venga eseguita simultaneamente una sola istanza di un agente di orchestrazione specifico, impedendo l'esecuzione simultanea di orchestrazioni duplicate. È possibile implementare questo modello singleton negli SDK delle attività Durable Functions o Durable Task SDK assegnando un ID istanza specifico a un agente di orchestrazione durante la creazione e quindi verificando se un'istanza con tale ID è già in esecuzione prima di avviarne una nuova.

Questo articolo illustra come implementare agenti di orchestrazione singleton con esempi di codice per ogni linguaggio supportato.

Prerequisiti

Annotazioni

Esiste una potenziale race condition nel modello singleton. Se due client eseguono simultaneamente la logica check-and-start, entrambe le chiamate potrebbero segnalare l'esito positivo, ma viene avviata una sola istanza di orchestrazione. A seconda dei requisiti, questo può avere effetti collaterali indesiderati. Se sono necessarie garanzie rigorose a istanza singola, è consigliabile aggiungere meccanismi di blocco aggiuntivi.

Importante

Attualmente, Durable Task SDK di PowerShell non è disponibile.

Esempio di orchestratore Singleton

L'esempio seguente illustra una funzione di attivazione HTTP che crea un'orchestrazione di processo in background singleton. Il codice tenta di assicurarsi che esista una sola istanza attiva per un ID istanza specificato.

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

Annotazioni

Il codice C# precedente riguarda il modello di lavoro isolato, che è il modello consigliato per le app .NET. Per altre informazioni sulle differenze tra i modelli di processi di lavoro isolati e in-process, vedere l'articolo Versioni di Durable Functions.

L'esempio seguente illustra come creare un'orchestrazione singleton usando gli SDK di Durable Task. Il codice tenta di assicurarsi che esista una sola istanza attiva per un ID istanza specificato.

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

Funzionamento del modello singleton

Poiché gli ID istanza sono univoci all'interno di un hub attività, la pianificazione di un'orchestrazione con un ID fisso noto e il controllo a priori del relativo stato impedisce esecuzioni simultanee duplicate. Per impostazione predefinita, gli ID istanza sono GUID generati in modo casuale. Negli esempi precedenti, tuttavia, viene passato un ID istanza specifico. Il codice recupera quindi i metadati dell'istanza di orchestrazione per verificare se un'istanza con tale ID è già in esecuzione. Se non è in esecuzione alcuna istanza di questo tipo, viene creata una nuova istanza con tale ID.

La funzione dell'agente di orchestrazione può usare qualsiasi modello, ovvero una funzione standard che avvia e completa o un'orchestrazione eterna che viene eseguita continuamente. Il modello singleton controlla solo il numero di istanze eseguite simultaneamente.

Passaggi successivi