How do I limit Concurrency of a Durable Azure Function with a Servicebus Queue Trigger?

Benedikt Schmitt 140 Reputation points
2025-03-24T13:13:08.6666667+00:00

Hello,

I have an Azure Function in python that is sending requests to an API. This API has limits on concurrent requests so I want to limit the number of concurrent calls from my Azure Function to four.

I am currently using the following settings:

host.json:
"extensions": {
    "serviceBus": {
      "maxMessageBatchSize": 1,
      "prefetchCount": 0,
      "maxConcurrentCalls": 4
    }
  },
local.settings.json:
"WEBSITE_MAX_DYNAMIC_APPLICATION_SCALE_OUT": 1,
"FUNCTIONS_WORKER_PROCESS_COUNT": 1

However every time I load messages into my Service Bus the Function App pulls more than 4 messages and also creates API calls for every message it pulls.

My preferred behaviour would be that the Function App only ever has four instances running and does not pull more messages until one of these four instances stops running.

How would I achieve this?

Azure Functions
Azure Functions
An Azure service that provides an event-driven serverless compute platform.
5,911 questions
{count} votes

1 answer

Sort by: Most helpful
  1. Sai Prabhu Naveen Parimi 2,265 Reputation points Microsoft External Staff Moderator
    2025-03-26T05:26:46.16+00:00

    @Benedikt Schmitt

    Based on your current setup, it looks like your Azure Durable Function is processing more than four concurrent messages despite setting maxConcurrentCalls to 4. To ensure strict concurrency control, here are a few key adjustments:

    1. Limit Function Scaling to a Single Instance

    You have already set WEBSITE_MAX_DYNAMIC_APPLICATION_SCALE_OUT = 1, which is correct. However, also check your Azure Portal → Function App → Scale Out settings and set Maximum Burst Limit = 1 to fully enforce single-instance scaling. More details on Azure Function scaling.

    1. Adjust Host Configuration for Concurrency Control

    Modify your host.json file to enforce concurrency limits:

    {
      "version": "2.0",
      "extensions": {
        "serviceBus": {
          "maxMessageBatchSize": 1,
          "prefetchCount": 0,
          "maxConcurrentCalls": 4,
          "autoCompleteMessages": false
        },
        "durableTask": {
          "maxConcurrentActivityFunctions": 4,
          "maxConcurrentOrchestratorFunctions": 1
        }
      },
      "functionTimeout": "00:10:00"
    }
    

    maxConcurrentCalls: 4 ensures only four messages are processed at a time. Service Bus trigger settings.

    maxConcurrentActivityFunctions: 4 restricts Durable Function activities to four concurrent executions.

    maxConcurrentOrchestratorFunctions: 1 prevents multiple orchestrator instances from running in parallel.

    autoCompleteMessages: false ensures messages are only marked complete after processing.

    1. Limit API Calls to 4 Concurrent Requests

    To enforce this at the function level, use a semaphore inside your activity function:

    import asyncio
    import requests
    
    semaphore = asyncio.Semaphore(4)  # Limit concurrent API calls to 4
    
    async def call_api(payload):
        async with semaphore:
            response = requests.post("https://example.com/api", json=payload)
            return response.status_code
    

    This ensures that even if multiple messages are received, only four API calls are made at any given time. Concurrency in Azure Functions.

    1. Handling Additional Messages

    Any messages beyond the four currently being processed will remain in the Service Bus queue and be picked up only when one of the ongoing executions completes. This ensures a controlled and sequential processing flow without exceeding the API’s concurrency limit.

    Let me know if you need any further clarification.


Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.