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:
- 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.
- 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.
- 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.
- 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.