A notification is a way that an application can share what it has done with the wider outside world in a you might be interested in this way. Notifications, especially when combined with Event Grid, allow for the creation of applications by composition of reactive components.
Introduction
A notification is a way that one application (or a microservice or function) can expose events to the rest of the world to tell them, "I have done x and you might be interested in it".
When a notification is sent out via Event Grid, subscribers can be added that react to this notification, and the advanced filtering and routing capabilities of event grid can be used to build sophisticated systems from composition of smaller components and routing rules.
Background
For an overview of all the features provided by Event Grid, I recommend this overview.
When designing a system based on notification events, I would recommend a technique such as Event Storming or Event Modelling.
Building a Notification Message to Send
Each custom notification message type your system will emit should populate an instance of Microsoft.Azure.EventGrid.Models.EventGridData
. This class defines the following properties:
public string Id { get; set; }
public DateTime EventTime { get; set; }
public string DataVersion { get; set; }
public string Topic { get; set; }
public string Subject { get; set; }
public object Data { get; set; }
public string EventType { get; set; }
Id
This is the unique identifier of the message, and can be used for deduplication. If your application does not have its own way of uniquely identifying a message, then setting it to a new GUID is valid.
EventTime
This should be set to when the event occurred. For distributed systems, I would use UTC as a common time format.
DataVersion
Set this version number to indicate which version of the message payload you are sending. You should increment this whenever you change the properties of the data payload and store the message payload definitions in a source control system or as a library that other applications can use.
EventType
This should be set to a string that uniquely identifies what event has happened. You can use dots in the event type to domain qualify it - for example, a new user being added might trigger an event: [Application].[Domain].UserAdded so that this can be differentiated from users being added to different applications or domains.
Subject
This is typically set to indicate who or what the notification was sent for. You can use a path separator to domain qualify this - for example, in the above user added notification, the subject could be [Application]/[Domain]/[User Identifier].
Data
This is where the payload of your notification message goes. You can put any object here so long as it can be serialised as JSON, but the entire message is limited to 64KB so if you have a big chunk of data, you are better off saving it to a public blob store and sending the URI in the event data.
Event Grid does allow for filtering by the content of the message. If you are doing that, then it is best to keep the data content small.
Sending the Notification Message
In order to transmit the message by Event Grid, you will need to know the event grid endpoint (to which the notification messages are posted) and the access key used to prove you have the rights to post to it. Typically, these would be stored in the configuration settings of your application rather than hard-coded.
public HttpMessageHandler HttpMessageHandler
{
get => httpMessageHandler;
set
{
httpClient?.Dispose();
httpMessageHandler = value;
httpClient = new HttpClient(httpMessageHandler);
httpClient.DefaultRequestHeaders.Add("aeg-sas-key", this.eventGridKeyValue);
}
}
As well as this, it is good practice to specify the "retry count" (the number of times the notification should be attempted if it fails) and the "retry interval" (the amount of time to wait between retries).
To send the event grid message, we need to turn it into JSON, then send it to the Event Grid end point.
private async Task SendNotificationAsync(
EventGridEvent[] eventGridEventArray)
{
string json = JsonConvert.SerializeObject(eventGridEventArray);
StringContent content = new StringContent(json, Encoding.UTF8, "application/json");
HttpResponseMessage result = null;
try
{
result = await httpClient.PostAsync(this.eventGridTopicEndpoint, content);
}
catch (Exception e)
{
if (null != _logger )
{
_logger.LogError(e.Message);
}
return;
}
using (result)
{
var body = await result.Content.ReadAsStringAsync();
if (result.IsSuccessStatusCode)
{
if (null != _logger)
{
_logger.LogInformation($"Sent notification via
{this.eventGridTopicEndpoint}" );
}
}
else
{
if (null != _logger)
{
_logger.LogError($"Failed to send notification -
{result.StatusCode} {result.Content}");
}
}
}
}
Points of Interest
Event Grid provides what is known as "at least once" delivery of messages. This means that it is possible (and is something you need to code for) that a message will be received more than once.
This can be done by deduplicatiing messages based on the unique message identifier or by making your notification message processing idempotent so that multiple copies of the message do not cause any extra effect.
History
- 7th June, 2020: First cut