Einführung in Azure Queue Storage

Warteschlangenspeicherung in Azure

Der Azure-Zoo wächst und wächst, doch heute wollen wir uns einmal mit einem Tierchen beschäftigen, welches oft eine weniger prominente Rolle einnimmt: die (Warte-)Schlange, oder technisch ausgedrückt: der Azure Queue Storage (oder auch einfach Azure Queue).

Wer sich schon einmal mit Nachrichtensystemen beschäftigt hat, wird bestimmt bereits die ein oder andere Queue-Technologie bzw. Message Broker (z.B. RabbitMQ) kennengelernt haben. Azure Queue ist im Vergleich eine sehr simple Technologie, die sich auf die Grundlage des Erhaltens und Abrufens von Nachrichten beschränkt, dafür aber in den allgemeinen Azure Storage integriert ist und vielfältige Schnittstellen mitbringt – auf diese Weise lässt sich z.B. sehr einfach eine Queue mit einer Azure Function füllen, was wir später noch zeigen werden. Für komplexere Message-Broker-Mechanismen wäre hingegen eher der Azure Service Bus einen Blick wert.

Um einen Azure Queue Storage zu erstellen, benötigt man natürlich eine Ressourcengruppe, und erstellt dann erstmal einen Storage Account.

Dieser bietet die allseits bekannten Blob-Container, File Shares, Tabellen, und eben die Queue:

Hier erstellt man nun eine Queue, und kann dann manuell Nachrichten eingeben:

Eine Nachricht kann entweder niemals ablaufen, oder nach maximal 7 Tagen, und sie kann wahlweise in Base64 verschlüsselt gespeichert werden. Ist sie erstellt, sieht das Ganze in etwa so aus:

Jede Nachricht bekommt also eine ID, den Text, das Erstelldatum, das Ablaufdatum, und einen Zähler, der mitzählt, wie oft die Nachricht abgerufen wurde. Man kann die älteste Nachricht per Mausklick „dequeuen“, also aus der Queue (endgültig) entfernen, oder die ganze Queue leeren. Und was die Funktionalität im Portal angeht, war es das dann im Grunde auch schon.

Wie arbeite ich nun also mit so einer Queue? Nun, wie bereits angekündigt bringt die Queue eine API mit, welche über verschiedene Code-Sprachen ansprechbar ist. Wir nehmen ganz gerne C# für einfaches Coding, und da gibt es im Speziellen dann ein entsprechendes NuGet-Package, das die benötigten Libraries installiert und auf den Namen Azure.Storage.Queues hört (Anmerkung: diese Library unterstützt leider per se kein .Net Framework, weshalb z.B. in Visual Studio 2015 oder älter auf die Vorgängerlibraries zurückgegriffen werden muss). Nehmen wir also mal an, wir haben irgendein System (das kann ein IoT-Device sein, eine Applikation, oder etwas völlig anderes), welches in der Lage ist, Nachrichten im JSON-Format an eine URL zu senden per POST-Request. Mit Hilfe der API können wir in wenigen Schritten eine Azure Function mit HTTP-Trigger bauen, die als Webhook solche Nachrichten empfangen und direkt in die Queue schreiben kann.

Wie eine Azure Function gebaut wird, wird in vielen Blogs und Foreneinträgen beschrieben und ist daher hier out of scope, aber der ganze Code, der für das Empfangen einer Nachricht und das Wegschreiben in eine Azure Queue benötigt wird, beläuft sich auf diese wenigen Zeilen:

				
					public static class ReceiveMessage
    {
        [FunctionName("ReceiveMessage")]
        public static async Task<IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] HttpRequest req,
            ILogger log)
        {
            try
            {
                string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
                string connectionString = Environment.GetEnvironmentVariable("QueueConnectionString");
                string queueName = Environment.GetEnvironmentVariable("QueueName");
                QueueClient queueClient = new QueueClient(connectionString,queueName);

                await queueClient.CreateIfNotExistsAsync();

                await queueClient.SendMessageAsync(requestBody);

                string responseMessage = "Message successfully posted to queue.";

                return new OkObjectResult(responseMessage);
            }
            catch(Exception ex)
            {
                string errorMessage = ex.Message;
                return new BadRequestObjectResult(errorMessage);
            }
        }
    }

				
			

Der FunctionName ist hierbei entscheidend dafür, wie die URL am Ende heißt, das AuthorizationLevel „Function“ verlangt außerdem die Authorisierung über einen Schlüssel, der extra für diese Funktion bereitgestellt wird. Über req.Body erhält man Zugriff auf die gesendete Nachricht, der QueueClient stellt die Verbindung zum Queue-Storage über den entsprechenden ConnectionString (zu erhalten im Azure Portal) und den Queue-Namen herstellt. Nun kann die gewünschte Queue erstellt werden, falls sie noch nicht existiert, und dann die vorher erhaltene Nachricht direkt per SendMessage-Befehl weitergeleitet werden. Anschließend sendet man noch eine individuelle Erfolgsnachricht sowie den entsprechenden Statuscode, und im Fehlerfall die Fehlermeldung und ebenfalls den entsprechenden Statuscode. Nun nur noch Bereitstellen in einer Function App und fertig ist der Webhook!

Testen kann man das dann z.B. über Postman:

Ähnlich einfach kann man Nachrichten auch wieder abrufen. Hierbei ist erwähnenswert, dass man vorhandene Nachrichten einerseits auch in-place aktualisieren kann, andererseits die nächste Nachricht anschauen („PeekMessage“) oder eben „dequeuen“ per ReceiveMessage. Abrufen lassen sich Nachrichten auch in Batches. Dabei ist es möglich, den Zeitraum anzugeben, für den eine Nachricht für andere Leser unsichtbar ist, um doppelte Verarbeitungen zu verhindern. Wird eine Nachricht in diesem Zeitraum nicht endgültig gelöscht, ist sie hinterher automatisch wieder lesbar, allerdings mit einem erhöhten Dequeue Count.

Wie man das umsetzt, können Sie aber am besten einmal selbst ausprobieren. Hilfe finden Sie auf den Microsoft-Seiten, z.B. unter Erste Schritte mit Azure Queue Storage mit .NET: Azure Storage | Microsoft Docs