In the previous part of the series we saw how to improve the reliability of responding to new blobs by introducing a queue.This required the introduction of a Storage Queue to the solution and also that the writer of new blobs also write a queue message.
In this article, instead of manually writing messages to a queue on blob creation, we use Event Grid events.
Azure Event Grid has support for Blob Storage, meaning that when a new blob is written, Event Grid will notice this. We can then trigger an Azure Function from this Event Grid event.
This approach can improve the reliability and responsiveness compared to using a simple blob trigger: “Blob storage events are reliably sent to the Event grid service which provides reliable delivery services to your applications through rich retry policies and dead-letter delivery.” [Microsoft]
Creating an Event Grid Triggered Function
The following Azure Function code is a modified version of the code used in the previous article:
public static class ProcessFoodBlobsEventGrid
{
private static readonly string[] _meats = { "steak", "chicken", "venison" };
[FunctionName("ProcessFoodBlobsEventGrid")]
public static void Run(
[EventGridTrigger]EventGridEvent blobCreatedEvent,
[Blob("{data.url}")] string foods, // assumes small blob size so using string not stream
[Blob("{data.url}.vegetarian")] out string vegetarian,
[Blob("{data.url}.nonvegetarian")] out string nonVegetarian,
ILogger log)
{
log.LogInformation("Processing a blob created event");
StorageBlobCreatedEventData createdEvent = ((JObject)blobCreatedEvent.Data).ToObject<StorageBlobCreatedEventData>();
log.LogInformation($"Blob: {createdEvent.Url}");
log.LogInformation($"Api operation: {createdEvent.Api}");
vegetarian = null;
nonVegetarian = null;
string[] foodLines = foods.Split(new[] { "\r\n", "\n" }, StringSplitOptions.RemoveEmptyEntries);
foreach (var food in foodLines)
{
var isMeat = _meats.Contains(food);
if (isMeat)
{
nonVegetarian += food + Environment.NewLine;
}
else
{
vegetarian += food + Environment.NewLine;
}
}
}
}
In the preceding code, the [EventGridTrigger]EventGridEvent blobCreatedEvent will cause the function to be trigged based on an Event Grid event being directed to the function.
The input blob binding [Blob("{data.url}")] string foods uses a binding expression and accesses the data.url property from the JSON data that’s contained in the event (this comes from the event schema for Blob Storage). The 2 output bindings also use the original blob path/name and append .vegetarian or .nonvegetarian. This implementation writes output blobs to the same container as the input blob. You could also use dynamic binding in Azure Functions with imperative runtime bindings to just extract the filename from the blob and write the output blobs to a different container.
Creating an Event Subscription for New Blobs
The function needs an event subscription to be created in Azure to recognize when new blobs are written and invoke the function. This can be done by navigating to the storage account (requires storage account v2) in the Azure Portal and clicking the Events link. You can then add a new event subscription as the following screenshot shows (note the Defined Event Types is set to Blob Created):
You can also specify subject filters to limit the event to a specific container and/or file type as the following screenshot shows:
You could also specify dead-lettering and retry policies in case the Function App is unable to respond.
Now when a blob is added, the event subscription will notice it and invoke the function.
Ultimately “Use the Event Grid trigger instead of the Blob storage trigger for blob-only storage accounts, for high scale, or to reduce latency.” [Microsoft]
If you want to fill in the gaps in your C# knowledge be sure to check out my C# Tips and Traps training course from Pluralsight – get started with a free trial.
SHARE: