简单来说,我们的任务是处理大量输入消息。
为了解决这个问题,我们决定使用 Azure 队列存储和 Azure Functions。 我们的 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 条消息推送到队列中,但只有大约 10-20% 的消息被 MessageController
处理。
某些消息未处理或处理延迟很长时间。看起来持久函数未能启动 б,但没有抛出异常。
我们有几个问题:
- 这个具有队列触发和持久功能的解决方案是否正确 处理消息队列或者有更好的方法通过队列触发持久函数?
- 运行持久函数有任何限制吗?
- 可以同时执行多少个持久函数?
最佳答案
- 是的,这是启动编排的完全有效的方式!
- 当然,here's some details on the architecture as it relates to performance and scalability .
- 我认为您在这里可能想问的是:可以同时执行单个持久函数定义的多少个编排实例?这确实是一个需要理解的非常重要的方面。编排函数本身是单线程,并且根据我上面给出的规模链接,在一组控制队列之间实现平衡。您可以阅读该文档以获取更多信息,但底线是您不想在编排功能中执行除实际编排之外的任何工作,因为它们限制了可扩展性。编排操作函数的行为与任何其他 Azure 函数类似,并且其可扩展性几乎没有限制。
为了简洁起见,您确实在上面的问题中删除了编排触发器中的一些代码,据我所知,但是在 await Task.WhenAll(...)
之后您到底在做什么? ?如果它包含任何类型的重要处理,您确实应该将其分派(dispatch)给第三个操作函数(例如 Function_3
)来执行,然后简单地从编排函数返回结果。
更新:我刚刚注意到您的函数被定义为async void
。如果我不得不猜测,这实际上会导致运行时出现问题。您可以尝试将其更改为异步任务
,看看您的问题是否消失?作为一般规则defining methods as async void
is frowned upon in .NET .
关于c# - 如何执行Azure队列触发的大量持久函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48591061/