Did someone say event-driven architecture?

Introduction#

Here we go, another brain dump to connect the dots on events in Azure. I’ve been using Event Hubs and Event Grids for a while, but one day I got stumped by the question:

“Why don’t you use Service Bus?”

And I had no answer.

We had been primarily using Event Grid, with functions subscribing directly to events. This seemed fine—Event Grid has built-in retry logic. But one day, our Azure Functions were down, and events simply dead-lettered instead of retrying. That’s when I knew I had to go deeper.

This post walks through a proof of concept (POC) where I set up an event-driven messaging system in Azure using Event Grid, Service Bus, Azure Functions, and Logic Apps. The goal was to understand how Service Bus and Event Grid interact, especially in scenarios where Event Grid alone might lead to event loss due to function downtime.

If you just want the step-by-step commands to deploy this POC, jump to the TL;DR Deployment Guide.

Why This POC? (Or, How I Learned to Use Service Bus)#

When I get into situations where I don’t know the answer, I dive in headfirst. And because I’ve been doing my AZ-204 certification prep, this felt like the perfect opportunity to truly understand Service Bus and Event Grid.

Key Discovery:#

  • Event Grid = Traffic Manager → Routes events but does not store them.
  • Service Bus = Message Queue → Holds messages until the subscriber (e.g., Azure Function) processes them.
  • Lesson: Expecting Event Grid to work as a queue is like expecting my 9-year-old daughter to do my taxes. She’s awesome, but taxes aren’t her job. Different tools for different jobs.

To explore this, I set up an event-driven architecture using Event Grid, Service Bus, Azure Functions, and Logic Apps, based on an LMS-SIS grade submission use case.


POC Overview: LMS-SIS Grade Processing System#

This POC simulates an LMS posting a grade and ensuring the event is processed reliably:

  1. The LMS posts a grade event to Azure Event Grid.
  2. Event Grid routes the event to an Azure Service Bus Queue.
  3. An Azure Function processes the message from Service Bus.
  4. The Function updates the SIS and posts a notification event to Azure Event Grid.
  5. Event Grid routes the event to an Azure Service Bus Queue.
  6. Azure Logic Apps sends an email/SMS to notify students.

High-Level Architecture:#

Image Description

Component Breakdown#
  • LMS Posts Grade:
    • An instructor posts a grade, which triggers an event in the system.
  • Event Grid:
    • Acts as a high-throughput event router, forwarding the event to appropriate subscribers based on the event type.
  • Grades-SubscriptionGrades-Queue:
    • Routes LMS Grade.Posted events to a Service Bus queue, which buffers messages for reliable delivery.
  • Grade-Processor (Azure Function):
    • Picks up messages from the Grades queue, updates the SIS with GPA/grade changes, and emits a Notification Event.
  • Notification-SubscriptionNotification-Queue:
    • Routes the Notification event into another Service Bus queue.
  • notification-app (Logic App):
    • Listens for new messages on the Notification queue and sends a notification (email or SMS) to the student.

Key Learnings & Takeaways#

1. Event Grid Filtering Matters#

  • Critical Step: Ensure you include the --included-event-types flag.

    --included-event-types Grade.Posted Grade.Modified Assignment.Submitted
    
  • Why? Without this, an Azure Function republishing an event to the same topic can cause circular loops, leading to hundreds of duplicate events.

Image Description

2. Why Service Bus Instead of Just Event Grid?#

  • Event Grid is stateless—it simply routes events but doesn’t persist them.
  • Service Bus provides durability—it stores messages until a function processes them.
  • If a function is down, Service Bus holds the message until it’s back, preventing lost events.

3. The Forced Repetition of a 4-Hour Sandbox is Actually a Good Thing#

If you’ve been following along, you know I’m using A Cloud Guru’s Azure sandbox, which means every 4 hours my entire setup gets wiped.

At first, this was annoying. But now? It’s actually a good thing—because it forces me to truly understand the process instead of getting lucky once.

4. Debugging Service Bus & Event Grid#

  • App Insights was essential for confirming function execution.

  • Event Grid & Service Bus Metrics helped track event flow.

  • Creating Logic Apps via CLI was painful; template deployment was required:


TL;DR Deployment Guide#

This is the full step-by-step guide for when I need to recreate this POC quickly after the A Cloud Guru session expires.

Step 1: Prerequisites and Define Environment Variables#

Install Required Tools#
  • Azure CLI → brew install azure-cli
  • Docker → brew install --cask docker
Set these in your terminal before running commands:#
# Azure Resource Group
RESOURCE_GROUP="1-d6f70dba-playground-sandbox"
SUBSCRIPTION_ID="9734ed68-621d-47ed-babd-269110dbacb1"
LOCATION="eastus"

# Azure Service Bus
SERVICE_BUS_NAMESPACE="edu-sb-namespace-sbox"
SERVICE_BUS_GRADES_QUEUE="edu-grades-queue-sbox"
SERVICE_BUS_NOTIFICATION_QUEUE="edu-notification-queue-sbox"
SERVICE_BUS_COMMUNICATION_QUEUE="edu-communication-queue-sbox"

# Azure Event Grid
EVENT_GRID_TOPIC="edu-event-grid-sbox"
EVENT_GRID_GRADES_SUBSCRIPTION="edu-event-grades-subscription-sbox"
EVENT_GRID_NOTIFICATION_SUBSCRIPTION="edu-event-notification-subscription-sbox"
EVENT_GRID_COMMUNICATION_SUBSCRIPTION="edu-communication-subscription-sbox"

# Azure Function
APP_SERVICE_PLAN_FUNCTION_APP="edu-function-app-plan-sbox"
FUNCTION_APP_NAME="edu-grade-processor-sbox"
STORAGE_ACCOUNT_NAME="edufuncstorsbox"

# Azure Logic Apps
APP_SERVICE_PLAN_LOGIC_APP="edu-notification-app-plan-sbox"
LOGIC_APP_NAME="edu-notification-app-sbox"

# Azure Application Insights
APP_INSIGHTS_NAME="edu-app-insights-sb"

Step 2: Login and Set Resource Group and Subscription#

Log into Azure#
az login
az account set --subscription "<SUBSCRIPTION_ID>"

az group create --name $RESOURCE_GROUP \
--location $LOCATION

Step 3: Create Service Bus and Message Queues#

Create Service Bus Namespace#
az servicebus namespace create \
--resource-group $RESOURCE_GROUP \
--name $SERVICE_BUS_NAMESPACE \
--location $LOCATION \
--sku Basic
Create Service Bus Queues#
az servicebus queue create \
--resource-group $RESOURCE_GROUP \
--namespace-name $SERVICE_BUS_NAMESPACE \
--name $SERVICE_BUS_GRADES_QUEUE

az servicebus queue create \
--resource-group $RESOURCE_GROUP \
--namespace-name $SERVICE_BUS_NAMESPACE \
--name $SERVICE_BUS_NOTIFICATION_QUEUE

Step 4: Create Event Grid, Event Routing, and Subscriptions#

Create Event Grid Topic#
az eventgrid topic create \
--name $EVENT_GRID_TOPIC \
--resource-group $RESOURCE_GROUP \
--location $LOCATION
Create Event Grid Grades Subscriptions#
az eventgrid event-subscription create \
--name $EVENT_GRID_GRADES_SUBSCRIPTION \
--source-resource-id "/subscriptions/$SUBSCRIPTION_ID/resourceGroups/$RESOURCE_GROUP/providers/Microsoft.EventGrid/topics/$EVENT_GRID_TOPIC" \
--endpoint-type servicebusqueue \
--endpoint "/subscriptions/$SUBSCRIPTION_ID/resourceGroups/$RESOURCE_GROUP/providers/Microsoft.ServiceBus/namespaces/$SERVICE_BUS_NAMESPACE/queues/$SERVICE_BUS_GRADES_QUEUE" \
--included-event-types Grade.Posted Grade.Modified Assignment.Submitted
Create Event Grid Notification Subscriptions#
az eventgrid event-subscription create \
--name $EVENT_GRID_NOTIFICATION_SUBSCRIPTION \
--source-resource-id "/subscriptions/$SUBSCRIPTION_ID/resourceGroups/$RESOURCE_GROUP/providers/Microsoft.EventGrid/topics/$EVENT_GRID_TOPIC" \
--endpoint-type servicebusqueue \
--endpoint "/subscriptions/$SUBSCRIPTION_ID/resourceGroups/$RESOURCE_GROUP/providers/Microsoft.ServiceBus/namespaces/$SERVICE_BUS_NAMESPACE/queues/$SERVICE_BUS_NOTIFICATION_QUEUE" \
--included-event-types Grade.Notification

Step 5: Create Azure Function To Process Events#

Create Storage Account for Azure Function#
az storage account create \
--name $STORAGE_ACCOUNT_NAME \
--resource-group $RESOURCE_GROUP \
--location $LOCATION \
--sku Standard_LRS
Create Function App Service Plan and Function App#
# Create Function App Service Plan
az appservice plan create --name $APP_SERVICE_PLAN_FUNCTION_APP \
--resource-group $RESOURCE_GROUP \
--location $LOCATION \
--sku B1


# Create Function App
az functionapp create \
--name $FUNCTION_APP_NAME \
--resource-group $RESOURCE_GROUP \
--plan $APP_SERVICE_PLAN_FUNCTION_APP \
--storage-account $STORAGE_ACCOUNT_NAME \
--functions-version 4 \
--os-type Windows \
--runtime dotnet

az monitor app-insights component create \
--app $APP_INSIGHTS_NAME \
--location $LOCATION \
--resource-group $RESOURCE_GROUP

Step 6: Create Logic App#

az deployment group create \
  --resource-group $RESOURCE_GROUP \
  --template-file logicapp-template.json \
  --parameters @logicapp-parameters.json

Step 7: Deploy and Configure the Function#

Deploy to Code to Azure Function#
func azure functionapp publish $FUNCTION_APP_NAME
Set Environment Variables for Azure Function#
# Get Service Bus Connection String
SERVICE_BUS_CONNECTION_STRING=$(az servicebus namespace authorization-rule keys list \
    --resource-group $RESOURCE_GROUP \
    --namespace-name $SERVICE_BUS_NAMESPACE \
    --name RootManageSharedAccessKey \
    --query primaryConnectionString \
    --output tsv)

# Get Event Grid Topic Endpoint
EVENT_GRID_TOPIC_ENDPOINT=$(az eventgrid topic show \
    --name $EVENT_GRID_TOPIC \
    --resource-group $RESOURCE_GROUP \
    --query endpoint \
    --output tsv)

# Get Event Grid Access Key
EVENT_GRID_ACCESS_KEY=$(az eventgrid topic key list \
    --name $EVENT_GRID_TOPIC \
    --resource-group $RESOURCE_GROUP \
    --query key1 \
    --output tsv)

# Get Application Insights Instrumentation Key
APPINSIGHTS_INSTRUMENTATIONKEY=$(az monitor app-insights component show \
    --app $APP_INSIGHTS_NAME \
    --resource-group $RESOURCE_GROUP \
    --query instrumentationKey \
    --output tsv)

echo $SERVICE_BUS_CONNECTION_STRING 
echo $EVENT_GRID_TOPIC_ENDPOINT
echo $EVENT_GRID_ACCESS_KEY
echo $APPINSIGHTS_INSTRUMENTATIONKEY
Set Environment Variables on Azure Function#
az functionapp config appsettings set \
    --name $FUNCTION_APP_NAME \
    --resource-group $RESOURCE_GROUP \
    --settings "ServiceBusConnection=$SERVICE_BUS_CONNECTION_STRING" \
               "EVENT_GRID_TOPIC_ENDPOINT=$EVENT_GRID_TOPIC_ENDPOINT" \
               "EVENT_GRID_ACCESS_KEY=$EVENT_GRID_ACCESS_KEY" \
               "APPINSIGHTS_INSTRUMENTATIONKEY=$APPINSIGHTS_INSTRUMENTATIONKEY"
Verify Deployment#
az functionapp show --name $FUNCTION_APP_NAME --resource-group $RESOURCE_GROUP

Step 8: Deploy & Test the Solution#

curl -X POST -H "aeg-sas-key: $(az eventgrid topic key list --name $EVENT_GRID_TOPIC --resource-group $RESOURCE_GROUP --query "key1" --output tsv)" \
  -H "Content-Type: application/json" \
  -d '[
      {
        "id": "'$(uuidgen)'",
        "eventType": "Grade.Posted",
        "subject": "Grade.Posted",
        "eventTime": "'$(date -u +"%Y-%m-%dT%H:%M:%SZ")'",
        "data": {
          "StudentId": "12345",
          "CourseId": "CSE101",
          "Grade": "A"
        },
        "dataVersion": "1.0"
      }
    ]' \
  "https://$EVENT_GRID_TOPIC.$LOCATION-1.eventgrid.azure.net/api/events?api-version=2018-01-01"

Step 9: Cleanup When Session Ends#

az group delete --name $RESOURCE_GROUP --yes --no-wait

Final Thoughts#

Now I understand Service Bus vs. Event Grid.
Next Steps:

  • Experiment with Azure Durable Functions as an alternative.
  • Improve event monitoring with App Insights telemetry.

This structure keeps everything repeatable and easy to follow. Looking forward to testing more Azure services!