我正在玩Azure Durable functions。我调用一个活动后,目前我在Orchestration函数中得到InvalidOperationException
。它抱怨检测到多线程执行。如果先前从不受支持的异步回调恢复了协调器功能,则会发生这种情况。
有没有人遇到过这样的问题?我做错了什么? 完整代码可在GitHub
上找到以下是编排功能的一行:
var res = await ctx.CallActivityAsync<int>("LengthCheck", "inputData");
LengthCheck
活动功能是:
[FunctionName("LengthCheck")]
public static Task<int> Calc([ActivityTrigger] string input)
{
var task = Task.Delay(TimeSpan.FromSeconds(5));
task.Wait();
return Task.FromResult(input.Length);
}
堆栈跟踪是:
ac6fd5cdd07a4dc9b2577657d65c4f27:功能'InpaintOrchestration (Orchestrator)',版本''因错误而失败。原因: System.InvalidOperationException:多线程执行 检测。如果协调器先前运行,则会发生这种情况 从不受支持的异步回调中恢复。
在 Microsoft.Azure.WebJobs.DurableOrchestrationContext.ThrowIfInvalidAccess()
在 Microsoft.Azure.WebJobs.DurableOrchestrationContext.d__47`1.MoveNext()
从抛出异常的上一个位置开始的堆栈跟踪结束
在System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务 任务)
在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务 任务)
在System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
答案 0 :(得分:2)
只要orchestrator函数以不支持的方式执行异步工作,就会发生此异常。 &#34;不支持&#34;在这种情况下,有效意味着await
用于非持久性任务(&#34;非持久性&#34;意味着它是来自除DurableOrchestrationContext
以外的某些API的任务)
您可以在此处找到有关orchestrator函数的代码约束的更多信息:https://docs.microsoft.com/en-us/azure/azure-functions/durable/durable-functions-checkpointing-and-replay#orchestrator-code-constraints。
以下是我快速扫描时代码中已破坏的规则:
Orchestrator代码应非阻止。例如,这意味着没有I / O,也没有调用Thread.Sleep或等效的API。如果协调者需要延迟,则可以使用CreateTimer API。
Orchestrator代码必须永远不会启动任何异步操作,除非使用DurableOrchestrationContext API。例如,没有Task.Run,Task.Delay或HttpClient.SendAsync。 Durable Task Framework在单个线程上执行orchestrator代码,不能与其他异步API调度的其他线程交互。
当我们检测到发生了不支持的异步调用时,会发生此异常。我注意到这个代码正在发生:
private static async Task SaveImageLabToBlob(ZsImage imageLab, CloudBlobContainer container, string fileName)
{
var argbImage = imageLab
.Clone()
.FromLabToRgb()
.FromRgbToArgb(Area2D.Create(0, 0, imageLab.Width, imageLab.Height));
using (var bitmap = argbImage.FromArgbToBitmap())
using (var outputStream = new MemoryStream())
{
// modify image
bitmap.Save(outputStream, ImageFormat.Png);
// save the result back
outputStream.Position = 0;
var resultImageBlob = container.GetBlockBlobReference(fileName);
await resultImageBlob.UploadFromStreamAsync(outputStream);
}
}
进行异步或阻止调用的正确方法是将它们包含在活动函数中,这些函数不具有任何这些约束。
在此扩展程序的更新版本(v1.3.2及更高版本)中,我们提供了指向异常消息中描述代码约束的文档的链接。
答案 1 :(得分:-1)
这也发生在我的持久协调器功能上。我必须摆脱活动函数调用的所有 .ConfigureAwait(false) 结尾。
//invoking First activity function
var id = await context.CallActivityAsync<Guid>(Function1, requestModel);
//invoking second activity function that uses data from the first activity function without ConfigureAwait(false)
var readModel = await context.CallActivityAsync<ReadModel>(Function2, id);
//invoking third activity function that uses data from the second activity function without ConfigureAwait(false)
await context.CallActivityAsync(Function3, cartReadModel);