azure servicebus maxConcurrentCalls 完全被忽略

azure servicebus maxConcurrentCalls totally ignored

我的 host.json 中有这些,但每次我 运行 函数它 运行 并行 运行 线程比 1 多(多达队列中有消息)

{
  "version": "2.0",
  "extensions": {
    "serviceBus": {
      "prefetchCount": 1,
      "messageHandlerOptions": {
        "maxConcurrentCalls": 1
      }
    }
  }
}

我的函数

 [FunctionName(nameof(ResourceEventProcessorFunction))]
    public async Task Run([ServiceBusTrigger("%TopicName%", "%SubscriptionName%", Connection = "ServiceBusConnection", IsSessionsEnabled = true)]Message message, IMessageSession messageSession, ILogger log)

或许您可以将 WEBSITE_MAX_DYNAMIC_APPLICATION_SCALE_OUT 设置为 1,使函数 运行 一次只能运行一个实例。

如果本地开发,可以在local.settings.json设置,如果在Azure portal开发,可以在Configuration -> Application settings设置。

注:

1.如果你设置WEBSITE_MAX_DYNAMIC_APPLICATION_SCALE_OUT为1,你的函数将不会横向扩展,只能运行在一个实例中。

2.除了设置WEBSITE_MAX_DYNAMIC_APPLICATION_SCALE_OUT,还需要设置maxConcurrentCalls为1

3. 此设置处于预览状态。 An app property for function max scale out 已添加,这是限制横向扩展的推荐方法。

更详细的可以参考这篇official document.

利用会话

由于您使用的是会话,因此您可以对所有消息使用相同的 sessionId,并且它们将由单个实例按顺序处理,而不管 host.json.

中的设置如何

https://docs.microsoft.com/en-us/azure/service-bus-messaging/message-sessions

使用 Singleton 属性

如果您不能将 sessionId 用于您的目的,您应该尝试在您的函数上使用 [Singleton] 属性。这将确保所有函数实例中只有一个实例将处理请求。

我们已经在生产中成功地为 WebJobs 工作,它应该同样适用于 Azure Functions。如果您有专门的应用程序服务计划,使用此属性应该就足够了。 不推荐消费计划

[Singleton] does work on functions. The Azure Function host will create or wait for a lock in the Azure Storage account. The lock is the host ID which should be the same for all hosts of an app across all instances - so all instances share this lock and will only allow one execution to occur at a time.

To test this I put 1000 queue messages at once on a function with [Singleton]. The function would wake up, emit the invocation ID, sleep, and then emit the invocation ID. After processing all 1000 I looked at logs and never saw invocation IDs overlap. Only one invocation would happen globally at a time.

https://github.com/Azure/azure-functions-host/issues/912#issuecomment-419608830

 [Singleton]
 [FunctionName(nameof(ResourceEventProcessorFunction))]
    public async Task Run([ServiceBusTrigger("%TopicName%", "%SubscriptionName%", Connection = "ServiceBusConnection", IsSessionsEnabled = true)]Message message, IMessageSession messageSession, ILogger log)

在消费计划中

继续上面的引用:

With that said I think the recommendation is: [Singleton] isn't recommended for consumption hosted function plans. If you have a dedicated app service plan it's fine (as you are paying for the instance anyway). If you want to enforce [Singleton] like behavior in a consumption plan you are likely best to:

  1. Set WEBSITE_MAX_DYNAMIC_APPLICATION_SCALE_OUT to 1 so you never scale to more than one instance
  2. Set the host.json file to only allow 1 concurrent execution at a time for that trigger (for instance a batch size of 1 for Azure Queues).

https://github.com/Azure/azure-functions-host/issues/912#issuecomment-419608830

{
  "version": "2.0",
  "extensions": {
    "serviceBus": {
      "prefetchCount": 1,
      "messageHandlerOptions": {
        "maxConcurrentCalls": 1
      }
    }
  }
}

所以问题是每条消息都有不同的 sessionId。 在 azure 中禁用订阅的 sessionId 解决了这个问题。

赏金详情如下:D azure docs并没有具体说明如何限制线程数,但我看起来有点不对劲。

MessageRecievePumpSessionRecievePump 一个使用 MaxConcurrentCalls 另一个使用 MaxConcurrentSessionsMaxConcurrentAcceptSessionCalls

如果您在订阅中包含会话(MaxConcurrentCalls 不起作用)请注意这一点,它仅在会话 ID 相同时才有效。 当会话不同时尝试使用 MaxConcurrentSessions 或 MaxConcurrentAcceptSessionCalls 但请注意没有关于此的文档....