如果简单,我们的任务是处理大量输入消息。为了解决这个问题,我们决定使用Azure队列存储和Azure功能。 我们有Azure Functions结构,类似于以下代码:
队列触发功能:
[FunctionName("MessageControllerExecutor")]
public static async void Run(
[QueueTrigger(QUEUE_NAME, Connection = QUEUE_CONNECTION_NAME)]string queueMessage,
[OrchestrationClient] DurableOrchestrationClient client,
TraceWriter log)
{
await client.StartNewAsync("MessageController", queueMessage);
}
耐用功能:
[FunctionName("MessageController")]
public static async void Run(
[OrchestrationTrigger] DurableOrchestrationContext context,
TraceWriter log)
{
if (!context.IsReplaying) log.Warning("MessageController started");
var function1ResultTask = context.CallActivityAsync<ResultMessage>("Function_1", new InputMessage());
var function2ResultTask = context.CallActivityAsync<ResultMessage>("Function_2", new InputMessage());
await Task.WhenAll(function1ResultTask, function2ResultTask);
// process Function_1 and Function_2 results
// ...
}
简单活动功能样本:
[FunctionName("Function_1")]
public static ResultMessage Run(
[ActivityTrigger] DurableActivityContext activityContext,
TraceWriter log)
{
var msg = activityContext.GetInput<InputMessage>();
int time = new Random().Next(1, 3);
Thread.Sleep(time * 1000);
return new ResultMessage()
{
Payload = $"Function_1 slept for {time} sec"
};
}
在队列上收到新项目时触发MessageControllerExecutor。 MessageController是一个持久的函数,它使用很少的简单活动函数来处理每条消息。
当我们将消息推送到队列时,MessageControllerExecutor函数立即启动并异步启动,触发MessageController并传递消息,因此它按预期工作。但我们面临的问题是并非所有MessageController函数都运行。例如,我们将100条消息推送到队列中,但MessageController仅处理了大约10-20%的消息。有些消息未经处理或延迟处理。虽然没有任何异常被抛出,但看起来耐用函数无法启动。
所以,我们有几个问题:
答案 0 :(得分:5)
为了简洁起见,您确实在上面的问题中忽略了您的业务流程触发器中的一些代码,我明白了,但您在await Task.WhenAll(...)
之后到底做了什么?如果它包含任何类型的重要处理,你应该真正将其转化为第三个动作函数(例如Function_3
),然后简单地从编排功能返回结果。
更新:我刚注意到您的功能定义为async void
。如果我不得不猜测,这实际上会导致运行时出现问题。您可以尝试将其更改为async Task
并查看问题是否消失?作为一般规则defining methods as async void
is frowned upon in .NET。
答案 1 :(得分:1)
Drew的回答有些延伸。您不应该使用Thread.Sleep()作为文档states,而是使用CreateTimer Api。