Dafür schauen wir uns das Szenario eines unserer Kunden an:
Mittels des Event Sourcing Patterns (2) werden verschiedene Events erzeugt und über ein Azure ServiceBus Topic (3) publiziert.
Einer dieser Event-Konsumer ist eine Azure FunctionApp im Consumption Plan, da sich die zu erwartende Last sehr ungleichmäßig über den Tag verteilt. Dank des Consumption-Plans sind die Kosten gering, wenn kaum Events auftreten. Sobald es nötig ist, erfolgt eine automatische Skalierung und wir haben die benötigte Leistung.
Problem ist nur, dass einige Events unbedingt in der richtigen Reihenfolge abgearbeitet werden müssen. Das ist jedoch nicht mehr sichergestellt, sobald die FunctionApp skaliert. Dann kann es nämlich dazu kommen, dass die Verarbeitung eines Events in einer Instanz eine Verarbeitung in einer anderen Instanz überholt, Stichwort „race condition“ (4). Um dem vorzubeugen, kann man im ServiceBus das Feature Message Sessions (5) benutzen.
Quelle: https://docs.microsoft.com/en-us/azure/service-bus-messaging/message-sessions
Hier für muss man bei der Erstellung einer Topic Subscription die Option „enable-session“ wie hier mittels Azure CLI (6) aktivieren, da dieses Feature nicht mehr im Nachhinein aktiviert werden kann.
„az servicebus topic subscription create --name mysubscription --namespace-name mynamespace --resource-group myresourcegroup --topic-name mytopic –-enable-session“
Zusätzlich muss im ServiceBusTrigger in der Azure FunctionApp der Session Support „IsSessionsEnabled“ aktiviert werden.
„[ServiceBusTrigger("%TopicName%", "%TopicSubscriptionName%", Connection = "ServiceBusConnection", IsSessionsEnabled = true)]“
Falls man versucht ohne „IsSessionsEnabled“ auf die Subscription zuzugreifen gibt es folgenden Fehlermeldung „Microsoft.Azure.ServiceBus: It is not possible for an entity that requires sessions to create a non-sessionful message receiver“
Nun muss noch beim Senden der Nachrichten in den ServiceBus Topic die SessionId gesetzt werden, da sonst die Nachrichten in der DeadLetterQueue mit dem Fehler „Session enabled entity doesn't allow a message whose session identifier is null.“ landen.
Nun werden alle Events, die zusammengehören, mit der gleichen SessionId markiert und auch garantiert in der richtigen Reihenfolge abgearbeitet, obwohl sich parallele Azure FunctionApp Instanzen um die zügige Verarbeitung kümmern.
P.S: Azure ServiceBus Queues unterstützen ebenfalls Sessions.
Links:
- Azure Functions Consumption plan hosting
https://docs.microsoft.com/en-us/azure/azure-functions/consumption-plan
- Event Sourcing pattern
https://docs.microsoft.com/en-us/azure/architecture/patterns/event-sourcing
https://martinfowler.com/eaaDev/EventSourcing.html - Service Bus queues, topics, and subscriptions
https://docs.microsoft.com/en-us/azure/service-bus-messaging/service-bus-queues-topics-subscriptions - Race condition:
https://de.wikipedia.org/wiki/Wettlaufsituation - Message sessions:
https://docs.microsoft.com/en-us/azure/service-bus-messaging/message-sessions - Azure CLI:
https://docs.microsoft.com/de-de/cli/azure/