🧪 Demo: Event Grid + Blob Storage + Azure Function🔗
1️⃣ Create a Storage Account🔗
az group create --name demo-rg --location eastus
az storage account create \
--name demoeventgridstore \
--resource-group demo-rg \
--location eastus \
--sku Standard_LRS \
--kind StorageV2
Create a container:
2️⃣ Create a Function App (event handler)🔗
Install extension if not installed:
Create resources:
az storage account create \
--name demofunctionstore \
--resource-group demo-rg \
--location eastus \
--sku Standard_LRS
az functionapp create \
--resource-group demo-rg \
--consumption-plan-location eastus \
--runtime python \
--functions-version 4 \
--name demo-eventgrid-func \
--storage-account demofunctionstore
3️⃣ Create an Event Grid Subscription🔗
Hook Blob Storage events to the Function:
az eventgrid event-subscription create \
--name demo-subscription \
--source-resource-id $(az storage account show \
--name demoeventgridstore \
--resource-group demo-rg \
--query id -o tsv) \
--endpoint-type azurefunction \
--endpoint $(az functionapp show \
--name demo-eventgrid-func \
--resource-group demo-rg \
--query id -o tsv)
4️⃣ Add Function Code🔗
Inside your Function App (can be done in VS Code or portal):
__init__.py
import logging
import json
import azure.functions as func
def main(event: func.EventGridEvent):
logging.info('Event received: %s', event.get_json())
result = json.dumps({
'id': event.id,
'data': event.get_json(),
'topic': event.topic,
'subject': event.subject,
'event_type': event.event_type
})
logging.info('Processed Event: %s', result)
This will log the event payload whenever triggered.
5️⃣ Trigger the Event🔗
Upload a test file:
az storage blob upload \
--account-name demoeventgridstore \
--container-name demo-container \
--name hello.txt \
--file hello.txt \
--auth-mode login
6️⃣ Verify🔗
Check logs of the Function App:
You should see Event Grid delivering the event with metadata like:
{
"id": "abcd-1234",
"data": {
"api": "PutBlob",
"clientRequestId": "...",
"requestId": "...",
"contentType": "text/plain",
"blobType": "BlockBlob",
"url": "https://demoeventgridstore.blob.core.windows.net/demo-container/hello.txt"
},
"topic": "/subscriptions/.../resourceGroups/demo-rg/providers/Microsoft.Storage/storageAccounts/demoeventgridstore",
"subject": "/blobServices/default/containers/demo-container/blobs/hello.txt",
"event_type": "Microsoft.Storage.BlobCreated"
}
🔑 Why do we need an Event Grid subscription?🔗
-
Event Grid itself is just an event router.
-
It listens to event sources (like Blob Storage, IoT Hub, custom topics).
-
But it doesn’t know where to send events unless you explicitly tell it.
-
An Event Grid subscription is the “routing rule”:
-
Defines which events you care about (filters by event type, subject, prefix/suffix).
- Defines where to send them (endpoint like Function, Logic App, Event Hub, Webhook).
Without a subscription, the events are generated but simply dropped — nothing consumes them.
📌 Example (Blob Storage → Function)🔗
- Blob Storage generates an event: “BlobCreated”.
- Event Grid sees it but needs a subscription.
-
The Event Grid subscription says:
-
Source =
demoeventgridstore
(Blob Storage). - Event Type =
Microsoft.Storage.BlobCreated
. - Target = Function
demo-eventgrid-func
. - Now, when a blob is uploaded → Event Grid matches subscription → delivers event to Function.
🧠 Analogy🔗
Think of it like YouTube:
- Blob Storage (publisher) = YouTube channel.
- Event Grid (event router) = YouTube platform.
- Event Grid Subscription = you clicking “Subscribe + Notify” to a channel.
- Function/Logic App = your phone getting the notification.
If you don’t subscribe, the channel is still publishing videos (events), but you’ll never see them.
✅ So, you need to create a subscription every time you want to connect an event source to an event handler.
Example🔗
🔹 Architecture Overview🔗
- Blob Storage → file lands (raw data).
- Event Grid (system topic) → automatically emits
BlobCreated
event. - Event Subscription → routes event to an Azure Function.
- Azure Function → parses event payload (which blob was uploaded) and calls Databricks Jobs API.
- Databricks Job → runs notebook/ETL to process the file.
🔹 Step 1. Create Storage Account🔗
This is the event source.
az storage account create \
--name mydatalake123 \
--resource-group myResourceGroup \
--location eastus \
--sku Standard_LRS \
--kind StorageV2 \
--hierarchical-namespace true
🔹 Step 2. Create an Event Handler (Azure Function)🔗
This Function will receive BlobCreated events and trigger Databricks.
az functionapp create \
--resource-group myResourceGroup \
--consumption-plan-location eastus \
--runtime python \
--functions-version 4 \
--name databrickstriggerfunc \
--storage-account mydatalake123
🔹 Step 3. Create Event Subscription🔗
Connect Blob Storage → Event Grid → Function.
az eventgrid event-subscription create \
--name blobCreatedToDatabricks \
--source-resource-id /subscriptions/<subId>/resourceGroups/myResourceGroup/providers/Microsoft.Storage/storageAccounts/mydatalake123 \
--endpoint-type azurefunction \
--endpoint /subscriptions/<subId>/resourceGroups/myResourceGroup/providers/Microsoft.Web/sites/databrickstriggerfunc/functions/<functionName>
🔹 Step 4. Function Code (Python)🔗
This Function will:
- Receive BlobCreated event.
- Extract blob URL.
- Call Databricks Jobs API (authenticated with Personal Access Token or Managed Identity).
import logging
import os
import requests
import azure.functions as func
# Databricks config
DATABRICKS_INSTANCE = os.environ["DATABRICKS_INSTANCE"] # e.g. https://adb-123456789012.12.azuredatabricks.net
DATABRICKS_TOKEN = os.environ["DATABRICKS_TOKEN"] # Store securely in Key Vault
DATABRICKS_JOB_ID = os.environ["DATABRICKS_JOB_ID"] # Job you want to trigger
def main(event: func.EventGridEvent):
result = event.get_json()
logging.info(f"Received event: {result}")
# Check for blob created event
if event.event_type == "Microsoft.Storage.BlobCreated":
blob_url = result.get("url")
logging.info(f"New blob detected: {blob_url}")
# Trigger Databricks job via REST API
url = f"{DATABRICKS_INSTANCE}/api/2.1/jobs/run-now"
headers = {"Authorization": f"Bearer {DATABRICKS_TOKEN}"}
payload = {
"job_id": DATABRICKS_JOB_ID,
"notebook_params": {
"input_blob": blob_url
}
}
response = requests.post(url, headers=headers, json=payload)
if response.status_code == 200:
logging.info("Databricks job triggered successfully")
else:
logging.error(f"Failed to trigger job: {response.text}")
🔹 Step 5. Databricks Job🔗
- Create a Job in Databricks (pointing to a Notebook/Delta Live Table).
- Add a parameter
input_blob
so the notebook knows which file to process.
Example Notebook:
dbutils.widgets.text("input_blob", "")
blob_url = dbutils.widgets.get("input_blob")
print(f"Processing file: {blob_url}")
# Example: Read from Blob/ADLS into Spark
df = spark.read.text(blob_url)
# Do ETL...
🔹 Step 6. Test It🔗
Upload a file to Blob Storage:
az storage blob upload \
--account-name mydatalake123 \
--container-name raw \
--name testdata.csv \
--file ./testdata.csv
Event Grid → Function → Databricks job → Notebook runs with the blob path.
🔹 Extras (Production Ready)🔗
- Secure secrets → Store
DATABRICKS_TOKEN
in Azure Key Vault and integrate with Function. - Retries → Event Grid automatically retries delivery (with exponential backoff).
- Dead-letter destination → configure a Blob container to store undelivered events.
- Monitoring → Use Application Insights on the Function + Event Grid metrics.
✅ With this setup, every time a new file lands in storage, your Databricks pipeline kicks in automatically — no polling needed, fully event-driven.