Event Grid with Azure Functions
Azure Functions and Azure Event Grid work together as one of the most powerful combinations in serverless architecture. Event Grid detects something happening across Azure, and Azure Functions runs your code automatically in response — with no servers to manage and no idle cost when nothing is happening.
How the Integration Works
An Azure Function with an Event Grid trigger activates the moment Event Grid delivers an event to it. The function receives the event data as a parameter, runs its logic, and finishes. Azure handles all infrastructure, scaling, and retry coordination.
+-----------------------+
| Event Source |
| (Blob Storage, |
| Resource Manager, |
| Custom App) |
+----------+------------+
|
| Sends event
v
+-----------------------+
| Event Grid Topic |
| + Subscription |
+----------+------------+
|
| Delivers event payload
v
+-----------------------+
| Azure Function | <-- Your code runs here
| (Event Grid |
| Trigger) |
| |
| Input: event object |
| Logic: your code |
| Output: any action |
+-----------------------+
Two Ways to Connect Event Grid to Azure Functions
Option 1 – Event Grid Trigger (Recommended)
The Event Grid Trigger is purpose-built for this integration. Event Grid pushes the event directly to the function. The function URL is registered automatically in the subscription.
Option 2 – Webhook Trigger via HTTP Trigger
You can also use an HTTP-triggered function as a webhook endpoint in an Event Grid subscription. This gives more control over the HTTP response but requires manual validation handling.
The Event Grid Trigger handles validation automatically. For production use, choose the Event Grid Trigger.Validation Handshake Explained
When you create a new Event Grid subscription pointing to any endpoint (including an Azure Function using HTTP Trigger), Event Grid sends a validation event first. The endpoint must respond correctly before Event Grid delivers real events.
Step 1: Create Subscription
Event Grid --> sends ValidationEvent to endpoint
{
"eventType": "Microsoft.EventGrid.SubscriptionValidationEvent",
"data": {
"validationCode": "512d38b6-c7b8-40c8-89fe-f46f9e9622b6"
}
}
Step 2: Endpoint Responds
Endpoint --> returns validationCode back to Event Grid
{
"validationResponse": "512d38b6-c7b8-40c8-89fe-f46f9e9622b6"
}
Step 3: Subscription Becomes Active
Event Grid --> now delivers real events
The Event Grid Trigger in Azure Functions handles this validation automatically. You write zero validation code.
Event Grid Trigger Function – Code Structure
C# Example
[FunctionName("ProcessBlobCreated")]
public static void Run(
[EventGridTrigger] EventGridEvent eventGridEvent,
ILogger log)
{
log.LogInformation("Event type: {type}", eventGridEvent.EventType);
log.LogInformation("Event subject: {subject}", eventGridEvent.Subject);
// Parse the event data
var blobData = eventGridEvent.Data.ToObjectFromJson<StorageBlobCreatedEventData>();
log.LogInformation("Blob URL: {url}", blobData.Url);
// Your business logic here
// e.g., generate thumbnail, extract text, send notification
}
Python Example
import azure.functions as func
import logging
import json
def main(event: func.EventGridEvent):
logging.info("Received event: %s", event.event_type)
logging.info("Subject: %s", event.subject)
# Access event data as a dictionary
data = event.get_json()
blob_url = data.get("url")
logging.info("Blob URL: %s", blob_url)
# Your business logic here
Real-World Example: Auto-Resize Images on Upload
Scenario
A web application stores user profile photos in Azure Blob Storage. Every uploaded photo needs a 200x200 thumbnail. Instead of resizing at upload time (which slows the upload API), Event Grid triggers a function to resize asynchronously.
FLOW DIAGRAM
User uploads photo.jpg
|
v
Azure Blob Storage (originals container)
|
| BlobCreated event fires
v
Event Grid System Topic
|
| Filter: subject ends with ".jpg"
v
Azure Function: ResizeThumbnail
|
| 1. Download original from URL in event data
| 2. Resize to 200x200
| 3. Upload thumbnail to "thumbnails" container
| 4. Update database record with thumbnail URL
v
Thumbnail saved: thumbnails/photo.jpg
Why This Pattern Works Well
| Aspect | Benefit |
|---|---|
| Upload speed | User gets immediate response; resizing happens in background |
| Cost | Function runs only when a photo uploads; zero idle cost |
| Scale | 100 simultaneous uploads trigger 100 function instances automatically |
| Reliability | Event Grid retries if function fails during resize |
Handling Multiple Event Types in One Function
One function can handle different event types from the same subscription. Use a switch statement to route logic based on the event type.
[FunctionName("StorageEventRouter")]
public static void Run(
[EventGridTrigger] EventGridEvent eventGridEvent,
ILogger log)
{
switch (eventGridEvent.EventType)
{
case "Microsoft.Storage.BlobCreated":
HandleBlobCreated(eventGridEvent, log);
break;
case "Microsoft.Storage.BlobDeleted":
HandleBlobDeleted(eventGridEvent, log);
break;
default:
log.LogWarning("Unknown event type: {type}", eventGridEvent.EventType);
break;
}
}
Output Bindings from Event Grid Functions
An Azure Function triggered by Event Grid can also produce output — writing to storage, sending a message, or even publishing new events.
Event Grid Event
|
v
+------------------+
| Azure Function |
| |---> Write to Cosmos DB
| Input: |
| Event payload |---> Send Service Bus message
| |
| |---> Publish new Event Grid event
+------------------+
This chaining pattern lets you build complex workflows entirely from serverless functions reacting to events.
Scaling Behavior
Azure Functions scale out automatically based on the number of incoming events. Event Grid can deliver events to multiple function instances simultaneously. The platform manages concurrency.Low traffic: Event Grid --> 1 function instance Medium traffic (50 events): Event Grid --> 5 function instances (10 events each) High traffic (500 events): Event Grid --> 50 function instances (auto-scaled)
For Consumption Plan functions, each instance handles one event at a time. For Premium Plan functions, concurrency per instance is configurable.
Error Handling and Retries
When a function throws an unhandled exception, it returns a 500 error to Event Grid. Event Grid then retries the event delivery using exponential backoff. If the function keeps failing, the event eventually goes to the dead letter storage.
Function throws exception
|
| Returns HTTP 500
v
Event Grid retries after 10 seconds
|
| Still fails
v
Event Grid retries after 30 seconds
|
| Still fails (after 24 hours total)
v
Event moved to Dead Letter Storage
Make your function code idempotent — running it twice with the same event should produce the same result. This prevents duplicate processing when Event Grid retries.
Best Practices
| Practice | Reason |
|---|---|
| Use Event Grid Trigger instead of HTTP Trigger | Automatic validation, cleaner code |
| Write idempotent functions | Safe against Event Grid retry duplicates |
| Keep function execution time short (under 5 minutes) | Avoids timeout-based delivery failures |
| Log the event ID at the start of each function | Makes duplicate detection easier in logs |
| Enable dead letter storage on every subscription | Captures events that exhaust all retries |
| Use filter rules on subscriptions | Reduces unnecessary function invocations |
