Page 24 - MSDN Magazine, September 2018
P. 24
Figure 3 Creating a Resource Group, Storage Account and Container
model to be notified of new events, which is another reason why serverless technologies such as Functions and Logic Apps for event handlers are appealing. Let’s put this into practice.
Setup
Now I’ll walk you through the steps of setting up and configuring both the retry policies and a dead letter endpoint. In addition, it would be great to also inspect the dead letter events and react to them immediately after they become available.
Everything I’m going to set up in Azure will be done from the Azure Cloud Shell. This will ensure that you can do it from any machine and not be at the mercy of any particular tools or other dependencies. Details about Azure Cloud Shell can be found at bit.ly/2CsFtQB.
At the time of this writing, this feature is in preview, though it most likely will be released before or shortly after the article is pub- lished. While it’s in preview, you’ll have to install the Event Grid extension to use it in the command-line interface (CLI):
az extension add -–name eventgrid
With that out of the way, I’m going to initialize a few local vari- ables that will be used repeatedly throughout the exercise:
rgname=msdndemo topicname=<your-unique-grid-topic-name> storagename=<your-unique-storage-account-name> containername=deadletterevents
I’m going to create a resource group, storage account and a con- tainer that will be used to receive the dead letter events, as shown in Figure 3.
Next, I need the storage account’s resource ID. This will be used, along with the container name, to define the dead letter endpoint:
# storage ID
storageid=$(az storage account show –-name $storagename
–-resource-group $rgname –-query id --output tsv)
# container ID for dead letter channel containerid="$storageid/blobservices/default/containers/$containername"
# create resource group
az group create --name $rgname -l westus2
# create storage account az storage account create \
-–name $storagename \ --location westus2 \ --resource-group $rgname \ --sku Standard_LRS \ --kind StorageV2 \ --access-tier Hot
# create storage container
export AZURE_STORAGE_ACCOUNT=$storagename
export AZURE_STORAGE_ACCESS_KEY=”$(az storage account keys list -– account-name $storagename
--resource-group $rgname –-query “[0].value” –-output tsv)” az storage container create –-name $containername
location for each event subscription. With this feature, I can now configure the dead letter channel to an Azure Storage Account that will capture the message and relevant details about its deliv- ery. This same endpoint will serve as both a dead letter and invalid message channel. Figure 2 illustrates how dead letter events are now supported in Azure Event Grid.
I want to call out a couple of important details before putting a sam- ple together that uses both the retry policies and dead letter delivery. Notice that the arrows coming from the Event Grid topic are going in the direction of the handlers. I wanted to point this out to reinforce the notion that Event Grid is a push-push model. Event handlers pro- vide a webhook that’s called by Event Grid when it’s time to send an event. This important design decision emphasizes the event-driven nature of the service. Unlike other messaging services, there’s no lon- ger a need to resort to long-polling or hammer-polling techniques to check if a message is available. Instead, a handler can rely on this
Figure 4 The Azure Function Event Handler
using System.IO;
using System.Linq;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http; using Microsoft.AspNetCore.Http;
using Microsoft.Azure.EventGrid.Models;
using Microsoft.Azure.WebJobs.Host;
using Newtonsoft.Json;
namespace WeWantTheFunc {
public static class SongRequestHandler {
[FunctionName("SongRequestHandler")] public static IActionResult Run(
[HttpTrigger(AuthorizationLevel.Function, "post", Route = null)]
HttpRequest req, TraceWriter log) {
// Get the body of the request
var requestBody = new StreamReader(req.Body).ReadToEnd();
// Check the header for the event type
if (!req.Headers.TryGetValue("Aeg-Event-Type", out var headerValues))
return new BadRequestObjectResult("Not a valid request");
var eventTypeHeaderValue = headerValues.FirstOrDefault(); if (eventTypeHeaderValue == "SubscriptionValidation")
{
// Validate the subscription
var events = JsonConvert.DeserializeObject<EventGridEvent[]>(requestBody); dynamic data = events[0].Data;
var validationCode = data["validationCode"];
return new JsonResult(new
{
validationResponse = validationCode });
}
else if (eventTypeHeaderValue == "Notification") {
// Handle the song request
log.Info(requestBody);
var events = JsonConvert.DeserializeObject<EventGridEvent[]>(requestBody);
// Reject the request if it does not // match the genre for the station.
if (events[0].Subject != "genre/blues")
return new BadRequestObjectResult("Sorry, this is a Blues station");
return new OkObjectResult(""); }
return new BadRequestObjectResult("Not a valid request"); }
} }
16 msdn magazine
Azure