Event Grid for Blob Storage: Filter by Subject and Dead-Letter Failed Deliveries Instead of Polling
Polling Blob Storage for new files wastes transactions and adds latency. Event Grid system topics can push BlobCreated events, but only if you filter subjects and handle dead-lettered failures properly.
05 Sept 2025, 05:16 UTC

Polling a Blob Storage container for new files is a common shortcut that quietly multiplies storage transactions and adds avoidable latency. Event Grid can push Microsoft.Storage.BlobCreated events to your code the moment a blob lands, but an unfiltered subscription on a busy container will drown your handler in logs, temp files, and thumbnails. The practical fix is a system topic paired with a subject suffix filter and a dead-letter container, so you process only the files you care about and never silently lose the deliveries that fail.
Why polling costs more than it looks
Listing blobs or checking timestamps on a timer turns every poll into a storage transaction. On a container with steady upload traffic, a one-minute interval generates hundreds of list operations per hour and still leaves a window where a file waits unnoticed. Event Grid emits events from the storage service itself, so latency drops to seconds and cost tracks actual writes rather than your polling frequency.
Filter by subject, not by guessing in code
Every Blob Storage event carries a subject property that contains the full blob path, for example /blobServices/default/containers/invoices/blobs/2026/q3-report.pdf. Event Grid advanced filters can match that subject by prefix or suffix, so a PDF-processing workflow can subscribe only to subjects ending in .pdf and ignore everything else.
Two details matter here. First, subject filters are case-sensitive and match the entire path, so .pdf will not match .PDF. Either normalize extensions on upload or add a second filter for the uppercase variant. Second, the filter is part of the subscription definition, not the handler, which means your endpoint receives fewer requests and you spend less compute discarding noise.
Dead-lettering captures delivery failures, not business errors
When Event Grid cannot deliver an event to your endpoint after its retry policy, it can store that event in a dead-letter container. This is a transport safety net, not an application error queue. It holds events when the endpoint is unreachable, authentication is rejected, or network rules block the path. It does not hold events your code received and then failed to process.
Configure a dead-letter container on a general-purpose v2 storage account and confirm the Event Grid resource has permission to write to it. Unprocessed dead-letter events accumulate and incur storage costs, so treat the container as a monitored signal: alert on object count and apply a lifecycle management rule if your recovery process is slower than your retention requirement.
Assume duplicates and retries
Event Grid retries failed deliveries with backoff and eventually expires events after a time-to-live window. Duplicate delivery is possible even when your endpoint is healthy. Your handler must be idempotent: before acting on a BlobCreated event, check whether that blob URL or ETag has already been processed, and verify the blob still exists. A BlobDeleted event can arrive moments after a create, so trusting the event type alone is fragile.
Worked example: create a filtered subscription with dead-lettering
The following commands run in Azure Cloud Shell or a local Azure CLI session. You need Contributor rights on the resource group and Storage Blob Data Contributor on the dead-letter container. Replace the placeholders with your own values. The source account must be a general-purpose v2 storage account; system topics are not available on legacy account types. For the webhook endpoint, prefer a short-lived credential such as a function key or managed identity rather than embedding a long-lived storage key in the subscription.
RESOURCE_GROUP="myResourceGroup"
LOCATION="eastus"
SOURCE_STORAGE_ACCOUNT="mystorageaccount"
DEADLETTER_STORAGE_ACCOUNT="mydeadletteraccount"
DEADLETTER_CONTAINER="eventgrid-deadletter"
TOPIC_NAME="blob-created-topic"
SUBSCRIPTION_NAME="pdf-processor"
ENDPOINT="https://myapp.azurewebsites.net/runtime/webhooks/eventgrid"
Create the system topic that watches the source storage account:
az eventgrid system-topic create \
--resource-group $RESOURCE_GROUP \
--name $TOPIC_NAME \
--location $LOCATION \
--source /subscriptions/<subscription-id>/resourceGroups/$RESOURCE_GROUP/providers/Microsoft.Storage/storageAccounts/$SOURCE_STORAGE_ACCOUNT \
--topic-type Microsoft.Storage.StorageAccounts
Create the subscription with a suffix filter and dead-letter endpoint:
az eventgrid event-subscription create \
--name $SUBSCRIPTION_NAME \
--source-resource-id /subscriptions/<subscription-id>/resourceGroups/$RESOURCE_GROUP/providers/Microsoft.Storage/storageAccounts/$SOURCE_STORAGE_ACCOUNT \
--endpoint $ENDPOINT \
--endpoint-type webhook \
--included-event-types Microsoft.Storage.BlobCreated \
--subject-ends-with .pdf \
--deadletter-endpoint /subscriptions/<subscription-id>/resourceGroups/$RESOURCE_GROUP/providers/Microsoft.Storage/storageAccounts/$DEADLETTER_STORAGE_ACCOUNT/blobServices/default/containers/$DEADLETTER_CONTAINER
Expected checks: Upload a file named sample.pdf and a file named debug.log to the source container. Only the .pdf upload should trigger your endpoint. Inspect the subscription with az eventgrid event-subscription show to confirm the suffix filter and dead-letter endpoint are present. Then temporarily point the endpoint at an unreachable host, upload another .pdf, wait for the retry window to pass, and confirm the event appears in the dead-letter container. Restore the endpoint and upload again to confirm delivery resumes.
Risks: Enabling a system topic on a high-traffic container increases both event delivery volume and storage operation counts. Validate the filter and dead-letter path in a non-production storage account before pointing the subscription at production data.
Trade-offs to accept before rollout
- Case sensitivity:
.pdfand.PDFare different subjects. Normalize uploads or add multiple filters. - Dead-letter drift: The container is not a retry queue. If nobody drains it, failed events pile up silently and cost money.
- Regional and version variance: Filter behavior, retry limits, and event schema details can vary by Event Grid API version and region. Confirm the exact behavior for your target region before enabling the subscription broadly.
- Event volume: A container with heavy write traffic can generate enough events to matter for cost and endpoint scaling. Estimate the rate during a representative burst.
Actionable closing
Before you enable a Blob Storage system topic in production, run this short checklist: test the suffix filter with both lowercase and uppercase extensions, verify the dead-letter container accepts writes from Event Grid, confirm your handler checks for prior processing, and review Event Grid delivery metrics after a realistic upload burst. If those four checks pass, you have replaced a polling loop with a push pipeline that ignores noise and surfaces failures instead of hiding them.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.