Share via

Coroutines in Azure Functions - EventHub processing - parallel processing of messages

Wentzler, Charlotte 41 Reputation points
2026-03-24T18:39:55.92+00:00

Good evening,

I have a Function App triggered by an EventHub, to which I do not have access (I was only provided a connection string), so I cannot increase partitioning. Our Function App doesn't seem to be able to keep up with the load, so I implemented and tested coroutines (Python, v1).

I can also see the behaviour that the Function App only processes the message batch once it is done with the previous batch (we are receiving batches of 100 messages), is there a way to not wait until the latest batch is processed to pick up the next? Can we configure this?

Thank you in advance!

Azure Functions
Azure Functions

An Azure service that provides an event-driven serverless compute platform.


2 answers

Sort by: Most helpful
  1. Pravallika KV 12,575 Reputation points Microsoft External Staff Moderator
    2026-03-24T18:56:53.38+00:00

    Hi @Wentzler, Charlotte ,

    Thanks for reaching out to Microsoft Q&A.

    By design, each partition hands you one batch at a time and won’t fetch the next batch until your function completes and checkpoints the current one. There isn’t a setting you can flip in the trigger to overlap batches on the same partition.

    Here are some approaches you can consider:

    1. In your host.json (for v1 you can still set these under the eventHub section), adjust maxBatchSize and prefetchCount so you pull smaller (or larger) batches in memory, avoiding long‐running single invocations.
    {
      "version": "2.0",
      "extensions": {
        "eventHubs": {
          "maxBatchSize": 100,
          "prefetchCount": 300,
          "batchCheckpointFrequency": 1
        }
      }
    }
    
    1. The only way to truly parallelize at the trigger level is more partitions. With more partitions, Azure Functions can spin up more hosts and distribute partitions across them. If you can’t change the Event Hub’s partition count, you could add consumer groups plus separate function instances (though you’ll have to handle de‐duplication or idempotency).
    2. Python v1 doesn't support dynamic concurrency or the more advanced host.json tuning that later versions do. Migrating to v2 on a Premium plan gives you dynamic concurrency, which can automatically pull multiple batches per partition as your app scales.
    3. If you need full control over parallelism, drop the built‐in trigger and write your own async receiver with the azure-eventhub library. Then you can spin up coroutines over messages or batches however you like.

    Hope this helps!


    If the resolution was helpful, kindly take a moment to click on User's imageand click on Yes for was this answer helpful. And, if you have any further query do let us know.


  2. Q&A Assist
    2026-03-24T18:40:12.1+00:00
    AI generated content. This question contains an answer created with AI from Q&A Assist. Learn more

    Event Hubs–triggered Functions process events per partition with a defined concurrency model. To increase parallelism and avoid effectively “one batch at a time” behavior, adjust concurrency and batching rather than relying only on coroutines inside a single invocation.

    Key options to increase throughput:

    1. Enable and tune batching
    • Ensure the Event Hubs trigger is configured for batch processing (cardinality = many in function.json for Python) so each invocation receives multiple events.
    • In host.json, increase:
      • maxEventBatchSize: maximum events delivered per invocation.
      • prefetchCount: should be ≥ maxEventBatchSize and often a multiple of it so the client caches more messages and can feed invocations faster.
    • Batching reduces per-invocation overhead and is recommended for performance.
    1. Increase per-instance concurrency
    • Azure Functions supports multiple concurrent executions per function app instance. For Event Hubs triggers, concurrency is controlled via host-level settings in host.json (fixed concurrency) or by enabling dynamic concurrency.
    • Increasing concurrency allows multiple batches to be processed in parallel on the same instance instead of strictly one after another.
    1. Use async code correctly
    • For I/O-bound workloads, use fully asynchronous code and avoid blocking calls. Mixing sync and async or blocking on async (sync over async) can cause thread-pool starvation and make the app appear to process only one batch at a time.
    • Ensure the function and all downstream I/O (HTTP calls, storage, etc.) are async end-to-end.
    1. Scale out and partition-level parallelism
    • Maximum parallelism is achieved when there is a one-to-one relationship between Event Hubs partitions and function instances (partition-level parallelism). With only a connection string and fixed partition count, this cannot be changed from the function side, but the Functions platform will still scale out instances (in Consumption/Premium plans) up to the number of partitions.
    • If throughput requirements exceed what the current Event Hubs tier/partitions can support, the upstream Event Hubs configuration (tier, partitions) must be adjusted by whoever owns that resource.
    1. Python-specific throughput tuning
    • For Python (single-threaded runtime), increase FUNCTIONS_WORKER_PROCESS_COUNT (up to 10) to run multiple worker processes per host instance.
    • For I/O-bound workloads, tune PYTHON_THREADPOOL_THREAD_COUNT to increase threads per worker, starting from (number of cores + 4) and adjusting based on observed throughput.

    These changes allow multiple batches to be processed concurrently across workers, threads, and instances, rather than waiting for one batch to complete before the next is handled.


    References:

    0 comments No comments

Your answer

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