如果我在运行的协调器上调用IDurableOrchestrationClient.TerminateAsync
,该协调器当前正在休眠并等待通过IDurableOrchestrationContext.CreateTimer
创建的持久计时器,这会导致包括计时器在内的整个进程正常关闭吗?
关于定时器的文档有一个非常明确的警告,关于优雅地取消任何未在编排中激活的定时器:
- https://learn.microsoft.com/en-us/azure/azure-functions/durable/durable-functions-timers?tabs=csharp#usage-超时
警告
如果代码不等待持久计时器完成,请使用CancellationTokenSource(.NET(或对返回的TimerTask(JavaScript(调用cancel((来取消持久计时器持久任务框架不会将编排的状态更改为";已完成";直到所有未完成的任务完成或取消
调用Terminate
会遵守这些限制吗?上面的文档根本没有说明这一点。
场景
我有一个要求,我需要";监视器";某个实例在创建后的一段时间内,并在实例被删除后停止监视它。
目前,我的应用程序在创建和删除实体时引发EventGrid事件,并在编排触发器活动中侦听这些事件:一旦收到创建事件,我就会启动监视该实例的编排。一旦接收到删除事件,我就会向协调器发送一个外部事件,通知它应该停止监视该实例并终止。当然,每个创建/删除对都由其自己的监视器处理(它们彼此隔离,由基于实体ID的显式实例ID控制(。
协调器逻辑基本上启动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);
}
但我不确定在处理持久定时器时终止执行是否安全(我找不到任何信息(。终止实例是否也会以优雅的方式终止计时器?这种方法会以任何方式改变功能使用/成本吗?或者,我应该保留ExternalEvent方法来优雅地显式取消执行?
这是来自https://github.com/Azure/azure-functions-durable-extension/discussions/2115
是的,终止编排是安全的,即使它有挂起的定时器(或者挂起的活动或子编排调用(。编排将始终转换到";"终止";状态实例终止后出现的任何消息(包括计时器消息(都将被静默丢弃。