在 Azure Durable Functions Orchestrator 中使用异步辅助函数是否安全?
Is it safe to use async helper functions in an Azure Durable Functions Orchestator?
我正试图在我们的持久函数项目中找出一些偶发的 Non-Deterministic workflow detected: TaskScheduledEvent: 0 TaskScheduled ...
错误。它很少见(在 10,000 次左右的情况下出现 3 次)。
在比较协调程序代码与约束 documented here 时,我们使用了一种我不清楚的模式。为了使协调器代码更多 clean/readable 我们使用一些私有异步辅助函数来进行实际的 CallActivityWithRetryAsync
调用,有时包装在异常处理程序中用于日志记录,然后主协调器函数 await
关于这个辅助函数。
类似于这个简化示例:
[FunctionName(Name)]
public static async Task RunPipelineAsync(
[OrchestrationTrigger]
DurableOrchestrationContextBase context,
ILogger log)
{
// other steps
await WriteStatusAsync(context, "Started", log);
// other steps
await WriteStatusAsync(context, "Completed", log);
}
private static async Task WriteStatusAsync(
DurableOrchestrationContextBase context,
string status,
ILogger log
)
{
log.LogInformationOnce(context, "log message...");
try
{
var request = new WriteAppDocumentStatusRequest
{
//...
};
await context.CallActivityWithRetryAsync(
"WriteAppStatus",
RetryPolicy,
request
);
}
catch(Exception e)
{
// "optional step" will log errors but not take down the orchestrator
// log here
}
}
实际上,这些任务与 Task.WhenAll
结合使用。调用这些 async
函数是否有效,尽管它们不是 直接 在 context
上?
是的,您正在做的事情是绝对安全的,因为它仍然会导致确定性行为。只要您不执行任何自定义线程调度或调用具有自己单独的异步回调的非持久 API(例如,网络 API 通常在单独的线程上具有回调 运行),就可以了。
如果您不确定,我强烈建议您使用我们的 Durable Functions C# analyzer 来分析您的代码是否存在编码错误。这将有助于标记任何可能导致 Non-deterministic workflow
错误的编码错误。
更新
注意:当前版本的分析器将要求您向私有异步函数添加一个 [Deterministic]
属性,如下所示:
[Deterministic]
private static async Task WriteStatusAsync(
DurableOrchestrationContextBase context,
string status,
ILogger log
)
{
// ...
}
这让它知道您的协调程序函数正在使用私有异步方法,并且还需要对其进行分析。如果您使用的是 Durable Functions 1.8.3 或更低版本,则 [Deterministic]
属性将不存在。但是,您可以使用相同的名称创建自己的自定义属性,分析器将遵守它。例如:
[Deterministic]
private static async Task WriteStatusAsync(
DurableOrchestrationContextBase context,
string status,
ILogger log
)
{
// ...
}
// Needed for the Durable Functions analyzer
class Deterministic : Attribute { }
但是请注意,我们计划在未来的版本中删除对 [Deterministic]
属性的需求,因为我们发现它实际上可能不是必需的。
我正试图在我们的持久函数项目中找出一些偶发的 Non-Deterministic workflow detected: TaskScheduledEvent: 0 TaskScheduled ...
错误。它很少见(在 10,000 次左右的情况下出现 3 次)。
在比较协调程序代码与约束 documented here 时,我们使用了一种我不清楚的模式。为了使协调器代码更多 clean/readable 我们使用一些私有异步辅助函数来进行实际的 CallActivityWithRetryAsync
调用,有时包装在异常处理程序中用于日志记录,然后主协调器函数 await
关于这个辅助函数。
类似于这个简化示例:
[FunctionName(Name)]
public static async Task RunPipelineAsync(
[OrchestrationTrigger]
DurableOrchestrationContextBase context,
ILogger log)
{
// other steps
await WriteStatusAsync(context, "Started", log);
// other steps
await WriteStatusAsync(context, "Completed", log);
}
private static async Task WriteStatusAsync(
DurableOrchestrationContextBase context,
string status,
ILogger log
)
{
log.LogInformationOnce(context, "log message...");
try
{
var request = new WriteAppDocumentStatusRequest
{
//...
};
await context.CallActivityWithRetryAsync(
"WriteAppStatus",
RetryPolicy,
request
);
}
catch(Exception e)
{
// "optional step" will log errors but not take down the orchestrator
// log here
}
}
实际上,这些任务与 Task.WhenAll
结合使用。调用这些 async
函数是否有效,尽管它们不是 直接 在 context
上?
是的,您正在做的事情是绝对安全的,因为它仍然会导致确定性行为。只要您不执行任何自定义线程调度或调用具有自己单独的异步回调的非持久 API(例如,网络 API 通常在单独的线程上具有回调 运行),就可以了。
如果您不确定,我强烈建议您使用我们的 Durable Functions C# analyzer 来分析您的代码是否存在编码错误。这将有助于标记任何可能导致 Non-deterministic workflow
错误的编码错误。
更新
注意:当前版本的分析器将要求您向私有异步函数添加一个 [Deterministic]
属性,如下所示:
[Deterministic]
private static async Task WriteStatusAsync(
DurableOrchestrationContextBase context,
string status,
ILogger log
)
{
// ...
}
这让它知道您的协调程序函数正在使用私有异步方法,并且还需要对其进行分析。如果您使用的是 Durable Functions 1.8.3 或更低版本,则 [Deterministic]
属性将不存在。但是,您可以使用相同的名称创建自己的自定义属性,分析器将遵守它。例如:
[Deterministic]
private static async Task WriteStatusAsync(
DurableOrchestrationContextBase context,
string status,
ILogger log
)
{
// ...
}
// Needed for the Durable Functions analyzer
class Deterministic : Attribute { }
但是请注意,我们计划在未来的版本中删除对 [Deterministic]
属性的需求,因为我们发现它实际上可能不是必需的。