Durable Task 中的单例编排器

对于后台作业,通常需要确保一次仅运行一个特定的编排器实例,以防止重复的编排同时运行。 可以在 Durable Functions 或 Durable Task SDKs 中实现单一实例模式,方法是在创建时将特定的实例 ID 分配给业务流程协调程序,然后检查具有该 ID 的实例是否已经在运行,再启动新的实例。

本文展示如何通过每种支持语言的代码示例实现单例协调器。

先决条件

注意

单一实例模式中存在潜在的竞态条件。 如果两个客户端同时执行检查和启动逻辑,则两个调用可能会报告成功,但实际上只有一个业务流程实例启动。 根据你的要求,这可能会产生不良的副作用。 如果需要严格的单实例保证,请考虑添加其他锁定机制。

重要

目前,PowerShell Durable Task SDK 不可用。

单例协调器示例

以下示例演示了一个 HTTP 触发器函数,该函数创建单例后台作业协调。 代码尝试确保指定实例 ID 仅存在一个活动实例。

这段 C# 代码使用独立工作进程模型,这是 .NET 应用的推荐模型。 有关进程内和独立工作者模型之间差异的更多信息,请参阅 Durable Functions 版本一文。

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

以下示例演示如何使用 Durable Task SDKs 创建单例协调。 代码尝试确保指定实例 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.");
}

单例模式的工作原理

由于实例 ID 在任务中心内是唯一的,因此计划具有已知、固定 ID 的业务流程,并首先检查其状态会阻止重复的并发运行。 默认情况下,实例 ID 是随机生成的 GUID。 但是,在前面的示例中,将传入特定的实例 ID。 然后,该代码提取业务流程实例元数据,以检查具有该 ID 的实例是否已运行。 如果未运行此类实例,则会使用该 ID 创建新实例。

协调器函数本身可以使用任何模式:启动和完成的标准函数,或持续运行的 永久协调。 单一实例模式仅控制并发运行的实例数。

后续步骤