Skip to content

Notification

Duncan Jones edited this page Oct 26, 2020 · 16 revisions

Notifications

Notification is how changes in one domain / system / application are communicated out to (and therefore acted upon by) other domains / systems / applications.

In this system there are two types of thing that we can raise notifications about : a new entity is created and a new event is appended to the event stream of an existing entity.

Background

A notification only says "this happened" and doesn't say what should be done with the thing that has happened.

A notification needs to indicate what it happened to. In this library that is done by the combination of Domain, Entity Type and Entity Instance Identifier.

For an event being appended to the event stream of an existing entity also needs to know the "as of" (when) of the event - which we send as the sequence number of the Event Stream

Technology

Notifications are sent via Azure Event Grid or Azure Storage Queues.

Notifications by Event Grid

By default notifications are sent by Event Grid which allows them to be used as part of an event carried state transfer based microservices solution.

The subject part is useful to allow event grid filtering so that subscribers can be notified only for specific new entities of a particular type or for specific event types being appended to the [event stream], rather than having to subscribe to all notifications and have the filtering performed internally.

As Azure Event Grid works on the promise of at least once delivery any recipient that needs uniqueness will need to track the message unique id.

In addition to the event payload data itself the notification message contains the context under which the event was written.

New entity notification

When a new entity (or event stream) is created a message like the following will be sent:

[
  {
    "id": "170259dc-aa00-47c1-855e-0052e35db99d",
    "subject": "eventsourcing/Domain Test/Entity Type Test Two/Instance 1234",
    "data": {
      "notificationId": "2176282c2eab4982a22db5bfa2dc71ba",
      "domainName": "Domain Test",
      "entityTypeName": "Entity Type Test Two",
      "instanceKey": "Instance 1234",
      "commentary": ""
    },
    "eventType": "Domain Test.Entity Type Test Two.NewEntity",
    "eventTime": "2019-09-22T20:02:19.4710404Z",
    "dataVersion": "1.0",
    "metadataVersion": "1",
    "topic": "/subscriptions/nnnnnnnn-nnnn-nnnn-nnnn-nnnnnnnnnnnn/resourceGroups/CQRS/providers/Microsoft.EventGrid/topics/eventstream-notifications"
  }
]

Event added notification

Whenever a new event is appended to an existing entity (event stream) a message like the following will be sent:-

[
  {
    "id": "2cedc82c-521d-45d3-a749-c552955bbdb5",
    "subject": "eventsourcing/Bank/Account/Money Withdrawn/A-001-123456-A",
    "data": { 
              "notificationId": "6eb417e5d301402a96d212db3601caa5", 
              "domainName": "Bank", 
              "entityTypeName": "Account", 
              "instanceKey": "A-001-123456-A", 
              "commentary": null, 
              "eventType": "Money Withdrawn", 
              "sequenceNumber": 1320, 
              "eventPayload": { 
                  "AmountWithdrawn": 100.0, 
                  "LoggedWithdrawalDate": "2020-01-21T20:33:47.2646028Z", 
                  "Commentary": "Added context to the event grid event details", 
                  "Target": null, "TransactionCorrelationIdentifier": null }, 
             "context": { 
                 "Who": null, 
                 "Source": "WithdrawMoney", 
                 "Commentary": null, 
                 "CorrelationIdentifier": null, 
                 "CausationIdentifier": "e9d72eda-0ebc-4c66-8fce-27a867f6f2fe", 
                 "SchemaName": null } 
          }
    "eventType": "Bank.Account.Money Withdrawn",
    "eventTime": "2019-09-22T20:02:19.6236918Z",
    "dataVersion": "1.0",
    "metadataVersion": "1",
    "topic": "/subscriptions/nnnnnnnn-nnnn-nnnn-nnnn-nnnnnnnnnnnn/resourceGroups/CQRS/providers/Microsoft.EventGrid/topics/eventstream-notifications"
  }
]

Entity deleted notification

When an existing entity (or underlying event stream) is deleted.

[
 {
    "id": "69b6cbba-83e5-4bd8-9b36-c8deeb3c5526 ",
    "subject": "eventsourcing/Bank/Account/AD-1912100958-NJ",
    "data": { 
             "notificationId": "69b6cbba83e54bd89b36c8deeb3c5526", 
             "domainName": "Bank", 
             "entityTypeName": "Account", 
             "instanceKey": "AD-1912100958-NJ", 
             "commentary": null, 
              "context": { 
                          "Who": null, 
                          "Source": "DeleteAccount", 
                          "Commentary": null, 
                          "CorrelationIdentifier": null, 
                          "CausationIdentifier": "459600fa-3040-425e-87be-701f3aa88bba", 
                          "SchemaName": null 
                          } 
             }
    "eventType": "Bank.Account.DeletedEntity",
    "eventTime": "2019-09-22T20:02:19.6236918Z",
    "dataVersion": "1.0",
    "metadataVersion": "1",
    "topic": "/subscriptions/nnnnnnnn-nnnn-nnnn-nnnn-nnnnnnnnnnnn/resourceGroups/CQRS/providers/Microsoft.EventGrid/topics/eventstream-notifications"
 }
]

Projection completed notification

Whenever a projection is executed to get state data for an entity from its event stream a notification is dispatched with that current state information.

[
  {
    "id": "2cedc82c-521d-45d3-a749-c552955bbdb5",
    "subject": "eventsourcing/Bank/Account/Balance/D-001-223456-B",
    "data": {
         "notificationId": "89488686a96148ff9c45b1e3f53aa6fd", 
         "domainName": "Bank", 
         "entityTypeName": "Account", 
         "instanceKey": "D-001-223456-B", 
         "projectionTypeName": "Balance", 
         "sequenceNumber": 61, 
         "asOfDate": "2020-01-27T00:00:00", 
         "commentary": "", 
         "value": { 
              "CurrentBalance": 106.33, 
              "CurrentSequenceNumber": 61
               } 
      }
    "eventType": "Bank.Account.Balance",
    "eventTime": "2020-01-30T20:02:19.6236918Z",
    "dataVersion": "1.0",
    "metadataVersion": "1",
    "topic": "/subscriptions/nnnnnnnn-nnnn-nnnn-nnnn-nnnnnnnnnnnn/resourceGroups/CQRS/providers/Microsoft.EventGrid/topics/eventstream-notifications"
  }
]

In addition to the state (or value) returned by the projection this notification also returns the sequence number of the last event from the event stream read by the projection to get that state and also (if applicable) the as of date and time the projection was run up to.

This can be used for passive update of downstream read-models (for example if another system takes the data of this system as its reference data) as well as logging and auditing functions.

Notifications by Storage Queue

Because the size of each message in a storage queue is significantly less (currently 64Kb) the notifications sent to a storage queue do not include any state information and so are best used for reactive processing rather than as part of an event carried state transfer system.

The message consists of a pipe separated string comprising a single letter which denotes what type of notification has occurred, the unique instance identifier it has occurred for, the notification class, sequence number and as-of date of the stream as at the time the notification was sent.

        /// <summary>
        /// Turn the properties passed in into a string to be sent via the queue
        /// </summary>
        /// <param name="targetEntity">
        /// What the notification occured for
        /// </param>
        /// <param name="NotificationType">
        /// The type of notification that occured 
        /// </param>
        /// <param name="asOfSequenceNumber">
        /// The sequence number of the event stream for which this notification occured
        /// </param>
        /// <param name="asOfDate">
        /// The as-of date of the event in the event stream for which this notification occured
        /// </param>
        /// <returns>
        /// A notification message < 64kb long as pipe-separated values
        /// </returns>
        public static string MakeMessageString(IEventStreamIdentity targetEntity,
            string NotificationType,
            string NotificationClass,
            int asOfSequenceNumber,
            DateTime? asOfDate = null
            )
        {
            if (asOfDate.HasValue)
            {
                return $"{NotificationType}|{NotificationClass}|{targetEntity.InstanceKey}|{asOfSequenceNumber}|{asOfDate}";
            }
            return $"{NotificationType}|{NotificationClass}|{targetEntity.InstanceKey}|{asOfSequenceNumber}";
        }

New entity notification

  • Notification type is N
  • Notification class is blank
  • As-of-date is null and the sequence number is zero

Event added notification

  • Notification type is E
  • Notification class the name of the event appended
  • As-of-date and the sequence number is the values for the [event stream] when the event was added

Entity deleted notification

  • Notification type is D
  • Notification class is blank
  • As-of-date is null and the sequence number is zero

Projection completed notification

  • Notification type is P
  • Notification class the name of the projection that was run
  • As-of-date and the sequence number is the values for the [event stream] when the projection completed

Classification completed notification

  • Notification type is C
  • Notification class the name of the classification that was run
  • As-of-date and the sequence number is the values for the [event stream] when the classification completed

Configuration

The following application settings control if / how notifications are sent out from the event sourcing back end:

  • RaiseEntityCreationNotification - set to "true" to send out notifications when a new event stream is created
  • RaiseEntityDeletionNotification - set to "true" to send out notifications when a new event stream is deleted
  • RaiseEventNotification - set to "true" to send out a notification when an event is appended to the event stream
  • RaiseProjectionCompletedNotification - set to "true" to send out a notification when a projection is executed
  • EventGridTopicEndpoint - The event grid endpoint to which the notifications will be sent
  • EventGridKeyValue - The SAS token to use to authenticate to that event grid topic end point
Clone this wiki locally