Introduction

Azure Functions on the Consumption plan automatically scales out by adding instances when trigger events increase. When the scale controller fails to respond, functions process events serially on a single instance, causing massive backlogs. This is critical for event-driven architectures processing queues, blobs, or Event Hubs.

Symptoms

  • Queue messages accumulate but only one Function App instance processes them
  • Azure Monitor shows single instance running despite high trigger count
  • FunctionExecutionCount metric is flat while queue depth grows
  • Scale controller logs show no new instance allocation events

Common Causes

  • Storage account used for triggers is in a different region than the Function App
  • App Service plan (not Consumption plan) selected - manual scaling required
  • Host.json maxPollingInterval set too high, delaying trigger detection
  • Scale controller throttled due to too many Function Apps in the subscription
  • Function App using premium plan with pre-warmed instances exhausted

Step-by-Step Fix

  1. 1.Check the hosting plan type:
  2. 2.```bash
  3. 3.az functionapp show --name my-function --resource-group my-rg \
  4. 4.--query '{Plan:serverFarmId,Sku:sku}'
  5. 5.`
  6. 6.Consumption plan shows sku: Y1. If it shows B1, S1, etc., you're on App Service plan and need to manually scale.
  7. 7.Check storage account region matches Function App region:
  8. 8.```bash
  9. 9.az functionapp config appsettings list --name my-function --resource-group my-rg \
  10. 10.--query "[?name=='AzureWebJobsStorage'].value"
  11. 11.`
  12. 12.The storage connection string should point to a storage account in the same region.
  13. 13.Optimize host.json trigger settings:
  14. 14.```json
  15. 15.{
  16. 16."version": "2.0",
  17. 17."extensions": {
  18. 18."queues": {
  19. 19."maxPollingInterval": "00:00:02",
  20. 20."batchSize": 16,
  21. 21."newBatchThreshold": 8,
  22. 22."maxDequeueCount": 5
  23. 23.}
  24. 24.}
  25. 25.}
  26. 26.`
  27. 27.Lower maxPollingInterval from default 1 minute to 2 seconds for faster response.
  28. 28.Check scale controller status:
  29. 29.```bash
  30. 30.az monitor metrics list \
  31. 31.--resource my-function \
  32. 32.--resource-group my-rg \
  33. 33.--metric "FunctionExecutionUnits" \
  34. 34.--interval PT1M \
  35. 35.--query 'value[0].timeseries[0].data'
  36. 36.`
  37. 37.Force scale-out by increasing concurrency:
  38. 38.For HTTP-triggered functions, increase maxConcurrentRequests in host.json:
  39. 39.```json
  40. 40.{
  41. 41."extensions": {
  42. 42."http": {
  43. 43."maxConcurrentRequests": 200,
  44. 44."maxOutstandingRequests": 300
  45. 45.}
  46. 46.}
  47. 47.}
  48. 48.`

Prevention

  • Use Consumption plan for automatic scaling
  • Keep trigger storage account in the same region as the Function App
  • Monitor FunctionExecutionUnits and queue depth with alerts
  • Set appropriate batchSize and polling interval for your workload
  • Consider Premium plan for predictable scaling with pre-warmed instances