Azure Event Hubs ingests millions of events per second. But the streaming layer is only as healthy as the consumers reading from it. Partition lag grows silently, consumer groups stall after a config change, and checkpoint stores get corrupted — none of which triggers an obvious alarm. Azure Monitor captures metrics inside your tenant, but it's as likely to fail during an outage as the service it's watching. Vigilmon adds an external, independent health layer: HTTP monitors on your processor services and heartbeat monitors for your event-driven workers.
This tutorial shows you how to wire Event Hubs consumers into Vigilmon for meaningful uptime monitoring.
What You'll Build
- A health endpoint on your Event Hubs processor that reports real partition status
- A Vigilmon HTTP monitor with appropriate timeout and assertion settings
- A heartbeat pattern for batch processors and Azure Functions event triggers
- A partition lag probe using Azure SDK
- An alerting strategy for consumer group failures
Prerequisites
- Azure subscription with at least one Event Hubs namespace and consumer application
- Azure CLI or Bicep/ARM configured locally
- A free account at vigilmon.online
Step 1: Add a Health Endpoint to Your Event Processor
Your Event Hubs consumer is typically a long-running service (AKS pod, App Service, Azure Container Apps). Add a /health route that checks real Event Hubs connectivity.
C# (ASP.NET Core)
// Endpoints/HealthEndpoint.cs
using Azure.Messaging.EventHubs;
using Azure.Messaging.EventHubs.Consumer;
public static class HealthEndpoint
{
public static void MapHealthEndpoint(this WebApplication app)
{
app.MapGet("/health", async (IConfiguration config) =>
{
var checks = new Dictionary<string, object>();
var ok = true;
try
{
await using var consumer = new EventHubConsumerClient(
EventHubConsumerClient.DefaultConsumerGroupName,
config["EventHubConnectionString"],
config["EventHubName"]
);
var partitions = await consumer.GetPartitionIdsAsync();
checks["eventHub"] = "ok";
checks["partitionCount"] = partitions.Length;
}
catch (Exception ex)
{
checks["eventHub"] = $"error: {ex.Message}";
ok = false;
}
return ok
? Results.Ok(new { status = "ok", service = "eventhubs-processor", checks })
: Results.Json(new { status = "degraded", service = "eventhubs-processor", checks },
statusCode: 503);
});
}
}
Python (FastAPI)
# routers/health.py
import os
from fastapi import APIRouter
from azure.eventhub import EventHubConsumerClient
from azure.eventhub.exceptions import EventHubError
router = APIRouter()
@router.get("/health")
async def health():
checks = {}
ok = True
try:
client = EventHubConsumerClient.from_connection_string(
os.environ["EVENTHUB_CONNECTION_STRING"],
consumer_group="$Default",
eventhub_name=os.environ["EVENTHUB_NAME"],
)
async with client:
partition_ids = await client.get_partition_ids()
checks["eventHub"] = "ok"
checks["partitionCount"] = len(partition_ids)
except EventHubError as e:
checks["eventHub"] = f"error: {e}"
ok = False
return {
"status": "ok" if ok else "degraded",
"service": "eventhubs-processor",
"checks": checks,
}
Node.js (Express)
// routes/health.js
import { EventHubConsumerClient } from "@azure/event-hubs";
export async function healthHandler(req, res) {
const checks = {};
let ok = true;
try {
const client = new EventHubConsumerClient(
"$Default",
process.env.EVENTHUB_CONNECTION_STRING,
process.env.EVENTHUB_NAME
);
const partitions = await client.getPartitionIds();
checks.eventHub = "ok";
checks.partitionCount = partitions.length;
await client.close();
} catch (err) {
checks.eventHub = `error: ${err.message}`;
ok = false;
}
res.status(ok ? 200 : 503).json({
status: ok ? "ok" : "degraded",
service: "eventhubs-processor",
checks,
});
}
Step 2: Configure the Vigilmon HTTP Monitor
- Log in to Vigilmon → Add Monitor → HTTP.
- URL: your processor service's health endpoint (e.g.
https://processor.example.com/health). - Check interval: 60 seconds.
- Response timeout: 15 seconds (Event Hubs client initialization can take a moment on cold start).
- Expected status:
200. - JSON assertion: path
status, expected valueok.
Tip: If your processor runs inside an Azure Virtual Network, expose the health port via an internal load balancer or Azure Application Gateway, then restrict Vigilmon's probe IPs in your NSG rules.
Step 3: Partition Lag Probe
Partition lag — events sitting unread in a partition — is the single most important Event Hubs health signal. Add a lag check to your health endpoint.
// Enhanced health endpoint with lag check
app.MapGet("/health", async (IConfiguration config) =>
{
var checks = new Dictionary<string, object>();
var ok = true;
long totalLag = 0;
await using var consumer = new EventHubConsumerClient(
config["ConsumerGroup"],
config["EventHubConnectionString"],
config["EventHubName"]
);
var partitions = await consumer.GetPartitionIdsAsync();
foreach (var partitionId in partitions)
{
var props = await consumer.GetPartitionPropertiesAsync(partitionId);
var lastEnqueued = props.LastEnqueuedSequenceNumber;
// Compare to your checkpoint store's last processed sequence
// (simplified: use your actual checkpoint logic here)
var checkpoint = await GetCheckpointSequenceNumber(partitionId);
var lag = lastEnqueued - checkpoint;
totalLag += lag;
if (lag > long.Parse(config["MaxPartitionLag"] ?? "10000"))
{
checks[$"partition_{partitionId}"] = $"lagging: {lag} events";
ok = false;
}
else
{
checks[$"partition_{partitionId}"] = $"ok (lag: {lag})";
}
}
checks["totalLag"] = totalLag;
return ok
? Results.Ok(new { status = "ok", checks })
: Results.Json(new { status = "degraded", checks }, statusCode: 503);
});
Step 4: Heartbeat Monitoring for Azure Functions Event Triggers
Azure Functions with Event Hubs triggers run on-demand — there is no persistent process to HTTP-probe. Use Vigilmon's Heartbeat monitor and ping it from inside the function after successful processing.
// Functions/EventProcessor.cs
[FunctionName("ProcessEvents")]
public async Task Run(
[EventHubTrigger("myeventhub", Connection = "EventHubConnection")] EventData[] events,
ILogger log)
{
foreach (var eventData in events)
{
var body = Encoding.UTF8.GetString(eventData.EventBody.ToArray());
await ProcessEvent(body, log);
}
// Ping Vigilmon heartbeat after successful batch
using var http = new HttpClient();
await http.PostAsync(
Environment.GetEnvironmentVariable("VIGILMON_HEARTBEAT_URL"),
null
);
log.LogInformation($"Processed {events.Length} events — heartbeat sent");
}
In Vigilmon, create a Heartbeat monitor:
- Set the grace period to 2–3× the maximum expected gap between event batches.
- If the function stops firing (trigger stalled, partition lease lost), the heartbeat goes silent and Vigilmon fires an alert.
Store the heartbeat URL as an application setting in Azure:
az functionapp config appsettings set \
--name my-function-app \
--resource-group my-rg \
--settings VIGILMON_HEARTBEAT_URL="https://vigilmon.online/api/heartbeat/<your-id>"
Step 5: Multi-Namespace and Consumer Group Strategy
For production Event Hubs setups with multiple namespaces or consumer groups, create one Vigilmon monitor per consumer group / processor service pair.
| Vigilmon monitor | What it watches |
|---|---|
| processor-ingest-$Default | Main ingest consumer, default group |
| processor-analytics-analyticsGroup | Analytics consumer, dedicated group |
| processor-archive-archiveGroup | Archive consumer, dedicated group |
| dlq-probe-heartbeat | Dead-letter / unprocessable events check |
Group all monitors under a single Status Page so stakeholders see one aggregate status rather than a wall of individual checks.
Step 6: Alerting Strategy
| Alert type | Recommended channel | |---|---| | Processor service 503 | Email + PagerDuty webhook | | Heartbeat missed (function stalled) | Slack webhook | | Partition lag threshold breached | Slack + email | | Multi-region namespace degraded | Status page + PagerDuty |
Set alert escalation: notify immediately on first failure, re-notify every 5 minutes if still down.
What Vigilmon Catches That Azure Monitor Misses
| Scenario | Azure Monitor | Vigilmon | |---|---|---| | Processor pod crashes (HTTP 503) | Needs container health probe + alert rule | HTTP monitor catches immediately | | Azure Function trigger stalls | Needs custom metric + alert | Heartbeat grace period fires alert | | Partition lag grows silently | Needs Consumer Lag metric + alert rule | Lag probe via health endpoint | | Azure Monitor itself is degraded | Self-monitoring blind spot | Vigilmon is external — unaffected | | Cross-region namespace failover | Needs geo-redundant alert config | One monitor per namespace, same alert channel |
Event Hubs makes high-throughput streaming look easy. What it doesn't do is tell you when your consumers fall behind or stop running. External monitoring from Vigilmon gives you the independent signal you need — before partition lag turns into data loss.
Start monitoring your Event Hubs processors in under 5 minutes — register free at vigilmon.online.