Azure Durable函数 - CallActivityAsync

时间:2018-03-25 15:39:26

标签: c# azure azure-functions

我正在玩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()

2 个答案:

答案 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);