Februar 2018

Band 33, Nummer 2

Azure: Ereignisgesteuerte Architektur in der Cloud mit Azure Event Grid

Von David Barkol

Dies ist eine aufregende Zeit für Cloudarchitekten. Das Innovationstempo hat eine Reihe neuer Herausforderungen und Technologien hervorgebracht, die die Art und Weise, wie Lösungen entworfen werden, verändern. Von diesem Wachstum profitieren die Entwickler und Architekten, die aus einer Fülle von Diensten und Optionen auswählen können.

Während Entwickler sich mit der Aufgabe beschäftigen, ihre Architekturen zu zerlegen, um neue Dienste wie Azure Functions, Logic Apps und andere zu nutzen, tauchen bekannte Hindernisse auf. In vielen Fällen stellen wir uns wieder einmal den „Klebstoff“ zusammen, der es ermöglicht, dass diese Dienste zusammenarbeiten. Mit der kürzlich erfolgten Einführung von Azure Event Grid soll diese Herausforderung gelöst werden, indem ein erstklassiger Ereignisroutingdienst in der Cloud bereitgestellt wird, der vollständig verwaltet, skalierbar und äußerst flexibel ist.

In diesem Artikel werde ich die Flexibilität von Azure Event Grid untersuchen und zeigen, wie damit bekannte Herausforderungen in Unternehmensanwendungen gelöst werden können. Ich empfehle Ihnen außerdem, die allgemeine Verfügbarkeitsankündigung von Event Grid unter aka.ms/egblog zu lesen.

Die Umkehrung von Abhängigkeiten

Das Konzept, Ereignisse in einer Lösung oder Anwendung zu verwenden, ist nicht neu. Tatsächlich setzt die ereignisgesteuerte Programmierung dieses Konzept bereits seit geraumer Zeit erfolgreich ein. Verleger-/Abonnentenwarteschlangen und GUIs sind nur einige der Beispiele, die diese Idee der Reaktion auf Ereignisse nutzen, die in einer Organisation, einer Anwendung oder einem System auftreten.

Einer der zentralen Ansatzpunkte einer ereignisgesteuerten Architektur ist die Umkehrung der Abhängigkeiten, die vorhandene Dienste untereinander aufweisen können. Abbildung 1 zeigt ein Beispiel für eine Reihe von Prozessen, die für die Kommunikation und Unterstützung einer Personalabteilung aufeinander angewiesen sind.

Dienste, die Programmlogik zu anderen Diensten enthalten
Abbildung 1: Dienste, die Programmlogik zu anderen Diensten enthalten

Damit dieser Entwurf funktionieren kann, muss jeder Dienst einige grundlegende Logik zu den anderen Diensten enthalten, um kommunizieren zu können. Diese Abhängigkeiten stellen Herausforderungen dar, und zwar nicht nur in Bezug auf die Größe, sondern auch aufgrund der Tatsache, dass diese Logik über die gesamte Architektur verstreut ist. Wenn sich diese Art von Lösungen ausdehnen, werden sie mit der Zeit schwierig zu warten und immer anfälliger, je mehr Änderungen und Abhängigkeiten eingeführt werden.

Als Alternative dazu entfernt das Konzept eines ereignisgesteuerten Entwurfs diese Abhängigkeiten, indem es die Idee eines Ereignisses als erstklassiges Element in der Architektur propagiert. Diese wichtige Überlegung ermöglicht es vielen anderen Systemen, einen zentralisierten Dienst zu nutzen, ohne die Last von Abhängigkeiten und Programmlogik, die über die gesamte Anwendung verteilt sind. Abbildung 2 verdeutlicht die Umkehrung der Abhängigkeiten für die Personalabteilungslösung durch die Einführung dieses Prinzips.

Ein zentraler Dienst, der Abhängigkeiten zwischen den anderen Diensten umkehrt
Abbildung 2: Ein zentraler Dienst, der Abhängigkeiten zwischen den anderen Diensten umkehrt

Dieser wichtige Dienst ist das, worum es im Rest des Artikels geht. Ich werde mich mit Azure Event Grid beschäftigen und untersuchen, wie Event Grid zur Unterstützung der nächsten Generation von Lösungen eingesetzt werden kann.

Vorstellung von Azure Event Grid

Azure Event Grid ist ein neuer, vollständig verwalteter Dienst, der das Routing von Ereignissen durch die Verwendung eines Verleger-/Abonnentenmodells unterstützt. Im Kern ist Event Grid ein Ereignisroutingdienst, der das Routing und die Zustellung von Ereignissen aus zahlreichen Quellen und von Abonnenten verwaltet. Abbildung 3, die aus der Übersichtsdokumentation von Event Grid (bit.ly/2qhaj9q) stammt, zeigt einige der Verleger und Handler, die heute mit Event Grid verwendet werden können.

Azure Event Grid: Übersicht
Abbildung 3: Azure Event Grid: Übersicht

Ein Ereignis wird von einem Herausgeber wie einem Blob Storage-Konto, Event Hubs oder sogar einem Azure-Abonnement erstellt. Wenn Ereignisse auftreten, werden sie an einem Endpunkt veröffentlicht, der als Thema bezeichnet wird, das der Event Grid-Dienst verwaltet, um alle eingehenden Nachrichten zu verarbeiten. Die Liste der Dienste unter Azure, die sich in Event Grid integrieren lassen, wird immer länger, und viele weitere sind bereits in Sicht.

Ereignisherausgeber sind nicht auf Dienste unter Azure beschränkt. Tatsächlich umfasst ein sehr häufiger Anwendungsfall Ereignisse, die von benutzerdefinierten Anwendungen oder Systemen stammen, die von überall aus ausgeführt werden können. Dazu gehören Anwendungen, die lokal, in einem Datencenter oder sogar in anderen Clouds gehostet werden. Diese Arten von Herausgebern werden als benutzerdefinierte Themen bezeichnet. Wenn sie eine HTTP-Anforderung an den Event Grid-Dienst posten können, sind sie Kandidaten für das Senden von Ereignissen.

Ereignishandler umfassen auch verschiedene Dienste unter Azure. Diese stellen einige der neuen serverlosen Technologien unter Azure vor, z.B. Functions und Logic Apps. Zusätzlich zu Azure Automation könnte eine andere Art von Ereignishandler jeder HTTP-Rückruf (auch als WebHook bezeichnet) sein. Handler werden bei Event Grid registriert, indem ein Ereignisabonnement erstellt wird. Wenn der Endpunkt des Ereignishandlers öffentlich zugänglich ist und mit TLS (Transport Layer Security) verschlüsselt wird, können Nachrichten aus Event Grid an ihn gepusht werden.

Im Gegensatz zu vielen anderen Azure-Diensten gibt es keinen Event Grid-Namespace, der bereitgestellt oder verwaltet werden muss. Themen für native Azure-Ressourcen sind integriert und für Benutzer vollständig transparent, während benutzerdefinierte Themen ad hoc bereitgestellt werden und in einer Ressourcengruppe vorhanden sind. Ereignisabonnements werden einfach einem Thema zugeordnet. Dieses Modell vereinfacht die Verwaltung von Themen als Abonnements und macht Event Grid mehrinstanzenfähig, wodurch eine massive horizontale Skalierung ermöglicht wird.

Azure Event Grid ist sprach- und plattformunabhängig. Obwohl Event Grid nativ in die Azure-Dienste integriert ist, kann Event Grid genauso einfach von allen Anwendungen oder Diensten genutzt werden, die das HTTP-Protokoll unterstützen, wodurch Event Grid zu einem sehr cleveren und innovativen Dienst wird.

Ereignisse oder Befehle

Bevor ich mich in irgendwelchen Code vertiefe und eine Lösung entwickle, die einige dieser Features aufzeigt, sollten wir uns den Unterschied zwischen einem Ereignis und einem Befehl ansehen. Die Unterscheidung kann manchmal subtil sein, aber sie ist wichtig zu verstehen, wenn Sie Systeme entwerfen, die auf Nachrichten beruhen.

Wenn an eine Nachricht eine bestimmte Aktion oder Antwort gesendet wird, handelt es sich höchstwahrscheinlich um einen Befehl. Wenn z.B. ein Mitarbeiter innerhalb einer Organisation befördert wird und eine Nachricht gesendet wird, um seinen neuen Vorgesetzten anzuweisen, ein Formular auszufüllen, dann trägt diese Nachricht einen bestimmten Zweck oder eine bestimmte Absicht mit sich. Da der Absender der Nachricht eine Erwartung hat und in manchen Fällen sogar eine Antwort erwartet, können wir dies als Befehl kategorisieren.

Wenn eine Nachricht ohne Kenntnis oder Erwartung der Art und Weise veröffentlicht wird, wie sie verarbeitet wird, wird sie als Ereignis angesehen. Nehmen wir an, dass innerhalb einer Organisation derselbe Mitarbeiter darum gebeten hat, seine E-Mail-Adresse zu ändern. Da diese Aktion für viele Systeme in der Organisation interessant sein könnte, aber nicht verlangt, dass der Herausgeber sich eines dieser Systeme bewusst ist, handelt es sich um eine Nachricht, die keine Absicht definiert. In diesem Fall informiert der Herausgeber lediglich mögliche Interessenten über das Eintreten eines Ereignisses. Es handelt sich um ein Ereignis und eindeutig um das Auftreten von etwas, das für einen Dienst wie Event Grid eine sinnvolle Option darstellt.

Ich könnte noch viel mehr Zeit damit verbringen, diese Unterschiede zu erläutern und darüber hinaus zu zeigen, wie ein geeigneter Messagingdienst unter Azure ausgewählt wird, aber das liegt außerhalb der Möglichkeiten dieses Artikels. Ich empfehle Ihnen, diesen aufschlussreichen Beitrag von Clemens Vasters zum Thema zu lesen: bit.ly/2CH3sbQ.

Szenario aus dem Personalwesen

Der beste Weg, um ein tieferes Verständnis von Event Grid zu erlangen, ist das Schreiben von Code, der die Fähigkeiten von Event Grid optimal nutzt. In diesem Artikel werde ich einige Ereignisse untersuchen, die aus einer fiktiven HR-Anwendung stammen. Ich veröffentliche Ereignisse zu einem benutzerdefinierten Thema und abonniere die Ereignisse dann mit verschiedenen Handlern.

Um die Sache einfach zu halten, werde ich zwei Arten von Ereignissen aus dem HR-System implementieren: wenn ein Mitarbeiter einer Organisation hinzugefügt wird und wenn ein Mitarbeiter entfernt wird. Diese Ereignisse sind eng genug miteinander verbunden, sodass sie Optionen bieten, die zeigen, wie Ereignisse auf unterschiedliche Weise gefiltert und verarbeitet werden können. Eine visuelle Darstellung der Lösung sehen Sie in Abbildung 4.

Eine Beispiellösung
Abbildung 4: Eine Beispiellösung

Auf hoher Ebene besteht die Lösung aus mehreren Schlüsselkomponenten, die ich in diesem Artikel erstellen werde. Sehen wir uns die Sache näher an.

„Employee Events“ ist ein Event Grid-Thema, an das die HR-Anwendung Nachrichten senden kann. Dazu gehören auch Ereignisse für neue und entfernte Mitarbeiter in der Organisation. Jede Nachricht enthält Informationen über den Mitarbeiter, seine Abteilung und die Art des Ereignisses.

„New Employee Welcome“ wird eine Logic App sein, die Nachrichten für neue Mitarbeiter in der Organisation abonniert. Sie wird schließlich eine Begrüßungs-E-Mail an den neuen Mitarbeiter senden.

„New Employee Equipment Order“ ist eine Azure Function, die Ereignisse für neue Mitarbeiter in der Engineeringabteilung abonniert. Sie erstellt dann eine Nachricht in einer Warteschlange für die weitere Verarbeitung.

„Employee Records“ ist eine benutzerdefinierte Website auf Basis von ASP.NET Core, die eine Web-API für den Empfang von Nachrichten bereitstellt, wenn Mitarbeiter das Unternehmen verlassen.

Erstellen eines benutzerdefinierten Themas

Zuerst einmal muss ich einige grundlegende Ressourcen in Azure erstellen. Sie können die Azure Cloud Shell entweder aus dem Portal heraus starten oder die Befehlszeilenschnittstelle (CLI) lokal verwenden. Details zur Verwendung der Cloud Shell finden Sie unter bit.ly/2CsFtQB. Wenn Sie die Cloud Shell noch nie verwendet haben, empfehle ich Ihnen diese Informationen ausdrücklich.

Als erstes werde ich eine Ressourcengruppe erstellen, um die Azure-Ressourcen zu verwalten und zu kapseln:

az group create --name <resource-group-name> --location <location>

Nachdem die Gruppe erstellt wurde, wird ein Event Grid-Thema bereitgestellt. Auf diese Weise wird ein Endpunkt für die Veröffentlichung benutzerdefinierter Ereignisse aus der HR-Anwendung bereitgestellt. Der Name des Themas muss für die Region eindeutig sein, da es sich um einen öffentlich zugänglichen Dienst unter Azure handelt. Der Standort muss sich auch in einer Region befinden, in der der Event Grid-Dienst verfügbar ist. Ich verwende normalerweise den Standort „westus2“ oder die Liste der Dienste, die in jeder Azure-Region angeboten werden (siehe bit.ly/2DU15ln).

az eventgrid topic create --name <topic-name> \
  --location <location> \
  --resource-group <resource group name>

Nach dem Ausführen des Befehls zum Erstellen des Themas werden Details zur Ressource zurückgegeben. Die Ausgabe wird ähnlich, aber nicht genau so aussehen wie der hier gezeigte Code:

{
  "endpoint": "https://<topic name>.westus2-1.eventgrid.azure.net/api/events",
  "id": "/subscriptions/xxxx-xxx-xx-xxx-xx/resourceGroups/eventgridsolution-rg/providers/Microsoft.EventGrid/topics/<topic name>",
  "location": "westus2",
  "name": "<topic name>",
  "provisioningState": "Succeeded",
  "resourceGroup": "eventgridsolution-rg",
  "tags": null,
  "type": "Microsoft.EventGrid/topics"
}

Notieren Sie sich den Endpunktwert. Er wird später bei der Veröffentlichung von Ereignissen verwendet. Außerdem benötigen Sie einen der beiden Zugriffsschlüssel, die für die Autorisierung generiert wurden. Um die Schlüssel abzurufen, können Sie die dem Thema zugeordneten Schlüssel auflisten. Sie können und sollten diese Schlüssel als Sicherheitsmaßnahme abwechselnd verwenden und erneut generieren (genau wie bei anderen Diensten unter Azure).

az eventgrid topic key list --name <topic-name> --resource-group <resource-group-name>

Wenn Sie es vorziehen, im Azure-Portal zu arbeiten, können Sie alle diese Optionen und Einstellungen auch dort erstellen und anzeigen.

Veröffentlichen eines Ereignisses

Bevor Sie das erste Ereignis senden, müssen Sie das Ereignisschema verstehen, das vom Thema erwartet wird. Jedes Ereignis verwendet unabhängig davon, ob der Herausgeber eine Azure-Ressource oder eine benutzerdefinierte Anwendung ist, die im folgenden Code beschriebene Struktur (eine hilfreiche Referenz für das Ereignisschema sowie einige Beispiele finden Sie unter bit.ly/2CG8oxI):

[
  {
    "topic": string,
    "subject": string,   
    "id": string,
    "eventType": string,
    "eventTime": string,
    "data":{
      object-unique-to-each-publisher
    }
  }
]

Zunächst muss darauf hingewiesen werden, dass Ereignisse in einem Array gesendet werden. Dies geschieht absichtlich, um die Möglichkeit zu bieten, mehrere Ereignisse innerhalb einer Anforderung zu senden. Ereignisse können in Batches gesendet werden, wodurch der Netzwerkdatenverkehr verringert wird und gleichzeitig Szenarien unterstützt werden, in denen die Konnektivität nicht immer verfügbar ist.

Das erste Ereignis, das ich veröffentlichen möchte, bezieht sich darauf, dass ein neuer Mitarbeiter in eine Organisation eintritt. Die Nutzlast für dieses Ereignis kann dem Inhalt von Abbildung 5 ähneln.

Abbildung 5: Ereignis „Mitarbeiter hinzugefügt“

[{
  "id": "30934",
  "eventType": "employeeAdded",
  "subject": "department/engineering",
  "eventTime": "2017-12-14T10:10:20+00:00",
  "data":{
    "employeeId": "14",
    "employeeName": "Nigel Tufnel",
    "employeeEmail": "nigel@contoso.com",
    "manager": "itmanager@contoso.com",
    "managerId": "4"
  }
}]

Später im Artikel werde ich die gleiche Struktur verwenden (mit einigen Unterschieden in den Werten), wenn ein Mitarbeiter die Organisation verlässt. Die folgenden Schlüsseleigenschaften gelten für dieses Ereignis:

eventType ist ein Wert, der zur eindeutigen Identifizierung des veröffentlichten Ereignistyps verwendet wird. Diese Eigenschaft kann von Handlern verwendet werden, die nur bestimmte Ereignistypen und nicht alle Typen abonnieren möchten.

subject ist ein Wert, der (wie eventType) verwendet wird, um zusätzlichen Kontext zum Ereignis bereitzustellen, mit der Option, Abonnenten auch einen zusätzlichen Filter zur Verfügung zu stellen. Ich werde sowohl eventType als auch subject bald nutzen, wenn ich die Abonnements erstelle. subject und eventType geben den Kontext des Ereignisses an.

data ist ein vom Herausgeber definierter Bucket, der einfach ein Objekt ist, das mindestens eine Eigenschaft enthalten kann. Herausgeber weisen relevante Informationen zum Ereignis selbst innerhalb dieser Eigenschaft zu. Beispielsweise enthält das Azure Blob-Speicherereignis Details zum erstellten oder gelöschten Blob wie URL und Inhaltstyp.

Um das Ereignis zu veröffentlichen, verwende ich Postman (oder ein ähnliches Tool), um die Nachricht zu simulieren, die von der HR-Anwendung an die oben genannte Endpunktadresse gesendet wird. Für die Autorisierung füge ich ein Element im Header hinzu, das als aeg-sas-key bezeichnet wird. Sein Wert ist einer der Zugriffsschlüssel, die beim Erstellen des Themas generiert wurden. Der Text der Anforderung enthält die in Abbildung 5 beschriebene Nutzlast.

Da es keine Abonnenten gibt, gibt es noch nichts zu beobachten. Der nächste Schritt wird sein, dies in Aktion zu sehen, indem Sie einige Ereignishandler für Event Grid erstellen, an die Ereignisse gepusht werden.

Verarbeiten von Ereignissen mit einer Azure-Funktion

Jetzt kommt der vergnügliche Teil des Abonnierens von Ereignissen. Unser erster Handler wird eine Azure-Funktion sein. Die Grundlagen zum Erstellen einer Funktion finden Sie unter bit.ly/2A6pFgu. In diesem Fall möchte ich speziell Ereignisse für neu hinzugekommene Mitarbeiter abonnieren. Darüber hinaus (und das ist ebenso wichtig) darf dieser Handler nur für Mitarbeiter aus der Engineeringabteilung aufgerufen werden.

Die meisten Beispiele führen Sie mithilfe des Azure-Portals schrittweise durch die Erstellung einer Funktion, was sehr einfach und schnell ist. Ich möchte Ihnen zeigen, wie Sie diese Aufgabe lokal aus Visual Studio erledigen können. Dies wird den Weg für weiteren produktionsbereiten Code ebnen. Ich werde auch ein Hilfsprogramm namens ngrok verwenden (siehe ngrok.com), um lokales Debuggen mit Event Grid zu unterstützen.

Wenn Sie dies nachvollziehen möchten, benötigen Sie ngrok sowie eine aktuelle Version von Visual Studio (ich habe für diesen Artikel Version 15.5.2 verwendet). Beginnen wir mit dem Erstellen eines neuen Projekts und der Auswahl von Azure Functions aus den Cloudvorlagen. Wählen Sie im Dialogfeld „Neues Projekt“ die Option „HTTP-Trigger“ aus, und behalten Sie die Standardwerte bei.

Aktualisieren Sie den Code für die Funktion so, dass er Abbildung 6 entspricht. Sie können die Datei auch umbenennen, um den Funktionsnamen widerzuspiegeln.

Abbildung 6: Implementierung für den neuen Mitarbeiterereignishandler

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.Azure.WebJobs.Host;
using Newtonsoft.Json;
namespace NewEmployeeApp
{
  public static class NewEmployeeHandler
  {
    public class GridEvent<T> where T : class
    {
      public string Id { get; set; }
      public string EventType { get; set; }
      public string Subject { get; set; }
      public DateTime EventTime { get; set; }
      public T Data { get; set; }
      public string Topic { get; set; }
    }
      [FunctionName("newemployeehandler")]
      public static async Task<HttpResponseMessage> Run(
        [HttpTrigger(AuthorizationLevel.Function, "post", Route = null)]
        HttpRequestMessage req,
        TraceWriter log)
         {
          log.Info("New Employee Handler Triggered");
          // Retrieve the contents of the request and
          // deserialize it into a grid event object.
          var jsonContent = await req.Content.ReadAsStringAsync();
          var gridEvent =
            JsonConvert.DeserializeObject<List<GridEvent<Dictionary<string,
              string>>>>(jsonContent)
              ?.SingleOrDefault();
            // Check to see if the event is available and
            // return an error response if its missing.
            if (gridEvent == null)
            {
              return req.CreateErrorResponse(HttpStatusCode.BadRequest,
                $@"Missing event details");
            }
          // Check the header to identify the type of request
          // from Event Grid. A subscription validation request
          // must echo back the validation code.
          var gridEventType = req.Headers.GetValues("Aeg-Event-Type"). 
            FirstOrDefault();
          if (gridEventType == "SubscriptionValidation")
          {
            var code = gridEvent.Data["validationCode"];
            return req.CreateResponse(HttpStatusCode.OK,
              new { validationResponse = code });
          }
          else if (gridEventType == "Notification")
          {
            // Pseudo code: place message into a queue
            // for further processing.
            return req.CreateResponse(HttpStatusCode.OK);
          }
          else
          {
            return req.CreateErrorResponse(HttpStatusCode.BadRequest,
              $@"Unknown request type");
          }
        }
  }
}

Es gibt hier wichtigen Code, den wir untersuchen sollten. Ganz am Anfang befindet sich eine Klasse namens GridEvent, die die Nutzlast und das Ereignisschema von Event Grid widerspiegeln soll. Idealerweise würde ich diese Klasse in einer allgemeinen Bibliothek platzieren, damit sie wiederverwendet werden kann. In diesem Beispiel wird sie verwendet, um den Inhalt der Anforderung in ein stark typisiertes Objekt zu deserialisieren.

Event Grid sendet an seine Abonnenten zwei Typen von Anforderungen (SubscriptionValidation and Notification), die Sie identifizieren können, indem Sie einen Wert aus dem Header untersuchen. Die Validierungsanforderung ist wichtig, um sicherzustellen, dass alle Abonnenten explizit hinzugefügt werden. Ich muss hier nur den Validierungscode zurückgeben, um zu bestätigen, dass ich Nachrichten empfangen kann:

var code = gridEvent.Data["validationCode"];
return req.CreateResponse(HttpStatusCode.OK,
  new { validationResponse = code });

Validierungsanforderungen können auch anhand ihres Ereignistyps identifiziert werden: Microsoft.EventGrid.SubscriptionValidationEvent. Wenn der Ereignistyp Notification ist, fahre ich mit der Implementierung der Geschäftslogik fort. Dieser defensive Programmieransatz wird dringend empfohlen, wenn Endpunkte für andere Dienste zugänglich sind.

Funktionen, die in Azure gehostet werden und auf die mit der Domäne azurewebsites.net verwiesen wird, erfordern keine Validierungslogik für Abonnements. Stattdessen werden sie von Event Grid zusammen mit einigen anderen Diensten wie Logic Apps und Rückrufen von Azure Automation-Runbooks auf die Whitelist gesetzt. Da ich vorhabe, lokal zu testen, muss ich den Validierungscode für Event Grid zurückgeben, um die Funktion als gültigen Endpunkt zu bestätigen.

Das Event Grid Runtime SDK wird einen Großteil dieses Setups übernehmen, von der Deserialisierung von Ereignissen und der Erstellung von stark typisierten Event Grid-Objekten bis hin zur automatischen Validierung von Endpunkten. Zum jetzigen Zeitpunkt waren die aktualisierten Runtime SDKs noch nicht verfügbar.

Lokale Funktionstests

Starten wir die Funktion aus Visual Studio, sodass sie lokal an Port 7071 ausgeführt wird. Sobald sie ausgeführt wird, öffnen Sie eine Eingabeaufforderung und verwenden ngrok, um einen sicheren Tunnel zu erstellen:

ngrok http -host-header=localhost 7071

Ich erhalte eine HTTPS-Adresse von ngrok, die ich als Abonnentenendpunkt verwenden kann. Die Adresse sollte https://d69f6bed.ngrok.io ähneln, aber bei jeder Ausführung des ngrok-Befehls eine andere Unterdomäne angeben. Fügen Sie die Route unserer Funktion an die URL an, sodass sie https://<generierter-wert>.ngrok.io/api/newemployeehandler ähnelt. Dies ist die Endpunktadresse für das Ereignisabonnement.

Wenn die Funktion ausgeführt und der sichere Tunnel eingerichtet ist, kann ich nun das Ereignisabonnement mit der CLI oder Azure Cloud Shell erstellen:

az eventgrid event-subscription create --name <event-subscription-name> \
  --resource-group <resource group name> \
  --topic-name <topic name> \
  --subject-ends-with engineering \
  --included-event-type employeeAdded \
  --endpoint <function endpoint>

Optional kann ich ein Ereignisabonnement aus dem Portal hinzufügen, indem ich das Dialogfeld ausfülle, wie in Abbildung 7 gezeigt.

Erstellen eines Ereignisabonnements über das Portal
Abbildung 7: Erstellen eines Ereignisabonnements über das Portal

Ich möchte einige wichtige Argumente bei der Erstellung des Ereignisabonnements benennen.

subject-begins-with (Präfixfilter) ist ein optionales Argument, das auf dem Präfix des subject-Felds in den Ereignissen basiert. Es handelt sich um eine literale Zeichenfolgenübereinstimmung. Platzhalterzeichen und reguläre Ausdrücke werden nicht unterstützt.

subject-ends-with (Suffixfilter) ist ein optionales Argument, das auf einem Suffix basiert, um Ereignisse zu filtern. Platzhalterzeichen und reguläre Ausdrücke werden nicht unterstützt.

included-event-type (Ereignistypen) ist eine optionale Liste von Ereignistypen, die abonniert werden können. Jeder Typ wird durch ein Leerzeichen getrennt.

Jetzt kann ich auf das frühere Beispiel für ein Veröffentlichungsereignis im Artikel zurückkommen, um sicherzustellen, dass die Ereignisse von Postman über Event Grid bis hin zur lokalen Funktion fließen. Sie können die Werte in der Anforderung ändern, um zu bestätigen, dass die Filter wie erwartet funktionieren.

Verarbeiten von Ereignissen: Logic App und WebHook

Das nächste Ereignisabonnement ist eine Logic App. Wie das Azure Function-Beispiel interessiert sie sich nur für den Ereignistyp „hinzugefügter Mitarbeiter“. Es werden keine Präfix- oder Suffixfilter genutzt, da ich eine Nachricht an Mitarbeiter aus allen Abteilungen senden möchte. Die fertige Version der Logic App sehen Sie in Abbildung 8.

Eine Logic App, die neue Mitarbeiter willkommen heißt
Abbildung 8: Eine Logic App, die neue Mitarbeiter willkommen heißt

Die Logic App beginnt mit einem Event Grid-Trigger. Wenn ich Microsoft.EventGrid.topics als Ressourcentyp auswähle, kann ich aus den benutzerdefinierten Themen im Abonnement auswählen.

Die Aktion „Parse JSON“ wird beim Zugriff auf die Eigenschaften im Datenobjekt hilfreich sein. Ich verwende diese Beispielnutzlast, um das Schema zu generieren:

{
  "id": "40000",
  "eventType": "employeeAdded",
  "subject": "department/finance",
  "eventTime": "2017-12-20T10:10:20+00:00",
  "data":{
    "employeeId": "24",
    "employeeName": "David St. Hubbins",
    "employeeEmail": "david@contoso.com",
    "manager": "finance@contoso.com",
    "managerId": "10"
  }
}

Als nächstes muss der Filter für den Ereignistyp mit einer Bedingungsaktion ausgeführt werden. Dies ist eine geringfügige Abweichung von der Art und Weise, wie das Ereignisabonnement mit der Funktion erstellt wurde, da es keine Möglichkeit gibt, diese Option im Event Grid-Trigger auszuwählen.

Im letzten Schritt wird eine E-Mail an den Mitarbeiter gesendet. Es werden die Eigenschaften verwendet, die im zweiten Schritt abgerufen wurden, um die Felder mit der Empfängeradresse und dem Betreff der E-Mail mit Daten aufzufüllen. Um die Logic App zu testen, klicken Sie im Designer auf „Ausführen“, und senden Sie wie zuvor eine Nachricht an den Endpunkt.

Das letzte Ereignisabonnement ist ein einfacher HTTP-Rückruf oder WebHook. Ich aktualisiere eine vorhandene ASP.NET Core-Anwendung mit einer Web-API für eingehende Ereignisse. Der Code für den WebHook wird der Azure-Funktion, die ich bereits früher geschrieben habe, sehr ähnlich sein. Einige subtile Unterschiede sind die Art und Weise, wie Headerwerte abgerufen werden, um den Anforderungstyp zu untersuchen, wie in Abbildung 9 gezeigt wird.

Abbildung 9: Ein Web-API-Controller, der Ereignisse empfängt

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
namespace EmployeeRecords.Controllers
{
  public class GridEvent<T> where T : class
  {
    public string Id { get; set; }
    public string Subject { get; set; }
    public string EventType { get; set; }
    public T Data { get; set; }
    public DateTime EventTime { get; set; }
  }
  [Produces("application/json")]
  [Route("api/EmployeeUpdates")]
  public class EmployeeUpdatesController : Controller
  {
    private bool EventTypeSubcriptionValidation
      => HttpContext.Request.Headers["aeg-event-type"].FirstOrDefault() ==
        "SubscriptionValidation";
    private bool EventTypeNotification
      => HttpContext.Request.Headers["aeg-event-type"].FirstOrDefault() ==
        "Notification";
    [HttpPost]
    public async Task<HttpResponseMessage> Post()
    {
      using (var reader = new StreamReader(Request.Body, Encoding.UTF8))
      {
        var jsonContent = await reader.ReadToEndAsync();
        var gridEvent =
          JsonConvert.DeserializeObject<List<GridEvent<Dictionary<string,
          string>>>>(jsonContent)
            .SingleOrDefault();
        if (gridEvent == null)
        {
          return new HttpResponseMessage { StatusCode = HttpStatusCode.BadRequest};
        }
        // Check the event type from Event Grid.
        if (EventTypeSubcriptionValidation)
        {
          // Retrieve the validation code and echo back.
          var validationCode = gridEvent.Data["validationCode"];
          var validationResponse =
            JsonConvert.SerializeObject(new { validationResponse =
            validationCode });
          return new HttpResponseMessage
          {
            StatusCode = HttpStatusCode.OK,
            Content = new StringContent(validationResponse)
          };
        }
        else if (EventTypeNotification)
        {
          // Pseudo code: Update records
          return new HttpResponseMessage { StatusCode = HttpStatusCode.OK };
        }
        else
        {
          return new HttpResponseMessage { StatusCode = HttpStatusCode.BadRequest };
        }
      }
    }
  }
}

Beim Erstellen des Ereignisabonnements sollte der registrierte Ereignistyp employeeRemoved sein. Diese Änderung erfüllt die Anforderung, dass der Handler nur Nachrichten für einen Mitarbeiter erhalten möchte, der aus der Organisation entfernt wurde. Beachten Sie auch, dass weder Präfix- noch Suffixfilter verwendet werden, weil der Abonnent bei jedem Vorkommen unabhängig von der Abteilung benachrichtigt werden möchte:

az eventgrid event-subscription create --name <event-subscription-name> \
  --resource-group <resource group name> \
  --topic-name <topic name> \
  --included-event-type employeeRemoved \
  --endpoint <function endpoint>

Denken Sie schließlich daran, dass der Endpunkt für das Ereignisabonnement sicher sein muss. Wenn Sie auf einen App Service unter Azure verweisen, müssen Sie HTTPS in der Adresse angeben, andernfalls schlägt das Hinzufügen des Abonnements fehl.

Zusammenfassung

Azure Event Grid ist wirklich ein Dienst, der zu wesentlichen Änderungen führt. In diesem Artikel habe ich ein gängiges Anwendungsintegrationsszenario behandelt. Event Grid wurde als die Technologie verwendet, die es ermöglicht, die Anwendung mit anderen Diensten wie einer Azure-Funktion, einer Logic App und sogar einem benutzerdefinierten WebHook zu verbinden, die sich überall befinden können. Ergänzt durch serverlose Apps zeigt Event Grid seine wahre Stärke, da beide Technologien zusammen die enormen Skalierungs- und Integrationsfunktionen nutzen können, die Azure unterstützt. Den Code in diesem Artikel finden Sie unter github.com/dbarkol/AzureEventGrid.


David Barkol ist ein Azure-Spezialist bei Microsoft im Global Black Belt Team. Kontaktieren Sie ihn auf Twitter: @dbarkol oder per E-Mail unter dabarkol@microsoft.com.

Unser Dank gilt den folgenden technischen Experten von Microsoft für die Durchsicht dieses Artikels: Bahram Banisadr und Dan Rosanovsanova
Dan Rosanova ist Principle Program Manager Lead und verantwortlich für die Azure-Messagingsuite mit Produkten wie Service Bus, Event Hubs, Azure Relay und Event Grid.
 
Bahram Banisadr ist der PM, der für Azure Event Grid verantwortlich ist. Er arbeitet daran, die Verbindungstechnologie für Azure-Dienste zu erstellen.


Diesen Artikel im MSDN Magazine-Forum diskutieren