终止正在等待计时器的协调器函数是否安全?

Is it safe to terminate an orchestrator function that is waiting on a timer?

如果我在 运行 协调器上调用 IDurableOrchestrationClient.TerminateAsync,该协调器当前正在休眠并等待通过 IDurableOrchestrationContext.CreateTimer 创建的持久计时器,这是否会导致整个进程正常关闭包括计时器?

有关计时器的文档有一个非常明确的警告,关于正常取消未在编排中激活的任何计时器:

Warning

Use a CancellationTokenSource (.NET) or call cancel() on the returned TimerTask (JavaScript) to cancel a durable timer if your code will not wait for it to complete. The Durable Task Framework will not change an orchestration's status to "completed" until all outstanding tasks are completed or canceled.

调用 Terminate 会遵守这些限制吗? The documentation on it 一点都没说清楚。

场景

我有一个需求,我需要在某个实例创建后“监视”它一段时间,并在实例删除后停止监视它。

目前,我的应用程序在创建和删除实体时引发 EventGrid 事件,我在编排触发器中收听这些事件 activity:一旦收到创建事件,我就启动监视该实例的编排.收到删除事件后,我会向编排器发送一个外部事件,以表示它应该停止监视该实例并终止。当然,每个 creation/deletion 对都由自己的监视器处理(它们彼此隔离,由基于实体 ID 的显式实例 ID 控制)。

编排器逻辑基本上触发 2 个任务并等待第一个完成:

  1. 一个计时器,基于创建的实例中的数据。这可以是几分钟,也可以是几个月
  2. 等待触发函数通知取消的WaitForExternalEvent

如果任务 2 获胜,我将取消计时器(根据建议),并退出函数。如果任务 1 获胜,我将在实例上执行我需要的处理并忽略外部事件。

协调器本身看起来像这样:

    [FunctionName(nameof(StartExpirationTracking))]
    public async Task StartExpirationTracking(
        [OrchestrationTrigger] IDurableOrchestrationContext context)
    {
        var entity = context.GetInput<Entity>();

        using var cancellationTokenSource = new CancellationTokenSource();
        var expirationTimeTask = context.CreateTimer(entity.ExpirationDate, cancellationTokenSource.Token);
        var stopTrackingEventTask = context.WaitForExternalEvent("StopTracking");

        var winner = await Task.WhenAny(expirationTimeTask, stopTrackingEventTask);
        if (winner == stopTrackingEventTask)
        {
            cancellationTokenSource.Cancel();

            return;
        }

        await ProcessExpiration(entity);
    }

那么问题就变成了:与其发送外部事件并等待它终止编排,不如直接从触发器调用 Terminate 是否安全?

这会稍微简化我的逻辑,因为我不需要关心编排中的任何外部事件并且可以这样做:

    [FunctionName(nameof(StartExpirationTracking))]
    public async Task StartExpirationTracking(
        [OrchestrationTrigger] IDurableOrchestrationContext context)
    {
        var entity = context.GetInput<Entity>();

        await context.CreateTimer(entity.ExpirationDate, CancellationToken.None);
        await ProcessExpiration(entity);
    }

但我不确定在处理持久计时器时终止执行是否安全(我找不到任何相关信息)。终止实例是否也会以优雅的方式终止计时器?这种方法会以任何方式改变函数 usage/costs 吗?或者我应该保留我的 ExternalEvent 方法以优雅地显式取消执行?

这是 https://github.com/Azure/azure-functions-durable-extension/discussions/2115

的更新交叉 post

是的,终止业务流程是安全的,即使它有未完成的未决计时器(或未决的 activity 或 sub-orchestration 调用,就此而言)。编排将始终转换为“已终止”状态。实例终止后出现的任何消息(包括计时器消息)都将被静默丢弃。