Orquestadores únicos en Durable Task

En el caso de los trabajos en segundo plano, a menudo debe asegurarse de que solo se ejecuta una instancia de un orquestador determinado a la vez, lo que impide que las orquestaciones duplicadas se ejecuten simultáneamente. Puede implementar este patrón singleton en Durable Functions o los SDK de tarea Durable Task asignando un identificador de instancia específico a un orquestador al crearlo y, a continuación, comprobando si ya se está ejecutando una instancia con ese identificador antes de iniciar una nueva.

En este artículo se muestra cómo implementar orquestadores singleton con ejemplos de código para cada lenguaje admitido.

Prerrequisitos

Nota:

Hay una posible condición de carrera en el patrón singleton. Si dos clientes ejecutan la lógica check-and-start simultáneamente, ambas llamadas podrían notificar el éxito, pero solo se inicia realmente una instancia de orquestación. Dependiendo de sus requisitos, esto puede tener efectos secundarios no deseados. Si se requieren garantías estrictas de instancia única, considere la posibilidad de agregar mecanismos de bloqueo adicionales.

Importante

Actualmente, el SDK de Durable Task de PowerShell no está disponible.

Ejemplo de orquestador singleton

En el ejemplo siguiente se muestra una función de desencadenador de HTTP que crea una orquestación de trabajo en segundo plano de singleton. El código intenta asegurarse de que solo existe una instancia activa para un identificador de instancia especificado.

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

Nota:

El código de C# anterior es para el modelo de trabajo aislado, que es el modelo recomendado para .NET aplicaciones. Para obtener más información sobre las diferencias entre los modelos de trabajador en proceso y en aislamiento, consulte el artículo Durable Functions versions.

En el ejemplo siguiente se muestra cómo crear una orquestación singleton mediante los SDK de Durable Task. El código intenta asegurarse de que solo existe una instancia activa para un identificador de instancia especificado.

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

Funcionamiento del patrón singleton

Dado que los identificadores de instancia son únicos dentro de un centro de tareas, programar una orquestación con un identificador conocido, fijo y comprobar su estado primero impide ejecuciones simultáneas duplicadas. De forma predeterminada, los identificadores de instancia son GUIDs generados aleatoriamente. Sin embargo, en los ejemplos anteriores se pasa un identificador de instancia específico. A continuación, el código captura los metadatos de la instancia de orquestación para comprobar si ya se está ejecutando una instancia con ese identificador. Si no se ejecuta ninguna instancia de este tipo, se crea una nueva instancia con ese identificador.

La propia función de orquestador puede usar cualquier patrón, una función estándar que inicia y completa o una orquestación eterna que se ejecuta continuamente. El patrón singleton solo controla cuántas instancias se ejecutan simultáneamente.

Pasos siguientes