Push Notifications

In einer klassischen Client-Server-Architektur stellt man sich den Server meist relativ schweigsam vor: Als „Dienstleister“ mit Zugriff auf die Datenbank wartet er auf Anfragen von Clients und beantwortet diese. Mit Hilfe von Push-Benachrichtigungen (Push Notifications) jedoch lässt sich die eigene Server-Anwendung deutlich extrovertierter, aktiver gestalten. In diesem Artikel wollen wir mögliche Anwendungsfälle für Push-Benachrichtigungen (Push Notifications) und damit verbundene Probleme betrachten.

Was sind Push Notifications?

Als „Push Notifications“ oder „Push-Benachrichtigungen“ bezeichnet man Nachrichten, die aktiv und selbstständig vom Server zum Client gesendet werden. Mit Hilfe solcher Nachrichten muss ein Client Daten also nicht länger vom Server abfragen, sondern bekommt Informationen ohne weiteres Zutun vom Server übermittelt. Wenn also ein Anwender eine Änderung an bestimmten Daten vornimmt, können alle anderen User als Reaktion darauf direkt über diese Änderung benachrichtigt werden. Im Gegensatz zu klassischen Pull-Abfragen (beispielsweise http GET-Requests) wird die Kommunikation vom Server initiiert und nicht vom Client. So können neue Informationen deutlich schneller verfügbar gemacht werden. Hier zunächst ein paar Beispiele wie Push in der Praxis eingesetzt wird.

Nachrichten an den User senden

Einer der einfachsten Anwendungsfälle von Push Notifications ist das Senden von simplen Textnachrichten, um den Anwender mit Informationen zu versorgen. Meist handelt es sich dabei um Systemnachrichten die anhand bestimmter Kriterien automatisch vom System ausgelöst werden, aber auch Chat-Nachrichten anderer Anwender könnten per Push verteilt werden. Clientseitig äußern sich solche Nachrichten meist in einfachen PopUps.

Listen aktualisieren

Etwas komplexer wird die Verwendung von Push Notifications im Zusammenhang mit Listen. Als Beispiel sei hier ein „Eingangskorb“ genannt, in dem Aufgaben gesammelt werden bis ein Anwender sie übernimmt und weiterverarbeitet. Mehrere Anwender greifen dabei auf den selben Eingangskorb zu und teilen sich so einen Aufgaben-Pool. Sobald eine neue Aufgabe im Eingangskorb landet, kann der Server sie mit einer Push-Benachrichtigung an alle verbundenen Clients senden, damit die Anwender die neue Aufgabe sofort sehen. Umgekehrt können die Clients auch benachrichtigt werden, sobald ein Anwender eine Aufgabe übernommen hat, wodurch das entsprechende Element aus der UI der anderen Clients entfernt wird. Der Aufgabenkorb des Anwenders wird praktisch in Echtzeit aktualisiert und zeigt ihm so stets den aktuellen Stand an. Auch der Inhalt dieser Aufgabenobjekte ließe sich mit einem solchen Mechanismus aktuell halten, ohne dass der Client eine Anfrage an den Server senden muss.
Technisch bedeutet das, dass die Notifications ausreichend Informationen mitsenden müssen, um die Aufgabe identifizieren und bei Bedarf anzeigen zu können. Andernfalls müssten die fehlenden Informationen separat nachgeladen werden, doch dazu unten mehr.

Objekte in Arbeit aktualisieren

Eine weitere Einsatzmöglichkeit von Push Notifications ist das Aktualisieren eines Objektes, welches gerade von mehreren Anwendern bearbeitet wird. In der Praxis stößt man hierbei häufig auf Konfliktsituationen, mit denen die Software umgehen können muss. Diese Konflikte lassen sich bei parallelem Arbeiten leider nicht vermeiden. Wenn die Änderungen eines Users jedoch direkt allen anderen Anwendern verfügbar gemacht werden, können diese auch entsprechend darauf reagieren. Das verringert die Wahrscheinlichkeit für auftretende Konflikte.

Gefahren

Push Notifications bieten eine gute Möglichkeit, um ein System noch dynamischer, schneller wirken zu lassen. Die bidirektionale Kommunikation zwischen Client und Server eröffnet Wege, um Informationen noch schneller zwischen den Anwendern auszutauschen. Daraus ergeben sich jedoch auch potentielle Probleme, mit denen wir umgehen müssen.

Mangelnde Zuverlässigkeit

Aus Sicht eines Clients sind Push Notifications per se nicht verlässlich. Im Unterschied zu klassischen Pull-Anfragen an den Server gibt es clientseitig keine Möglichkeit der Fehlerbehandlung falls eine Push-Benachrichtigung verloren geht, denn der Client weiß ja nichts von der verloren gegangenen Nachricht.
Nehmen wir das Beispiel des Eingangskorbes. Die Software zeigt dem Anwender eine Liste von Elementen an. Diese Liste wird in Echtzeit aktualisiert, es kommen also immer wieder neue Elemente hinzu oder bereits bearbeitete Elemente werden entfernt. Nun verliert der Client für ein paar Sekunden die Verbindung zum Server, beispielsweise weil der Anwender seinen Laptop zuklappt und zu einem Meeting geht. Und just zu diesem Zeitpunkt wird ein neues Element erstellt, welches aber aufgrund der fehlenden Verbindung nicht im Eingangskorb unseres gerade abwesenden Anwenders landet. Dieser klappt seinen Laptop ein paar Minuten später wieder auf und findet seinen Eingangskorb unverändert vor. Da ihm das neue Element nicht angezeigt wird bleibt es vorerst unbearbeitet liegen.
Unser Client braucht also zusätzliche Mechanismen zur Aktualisierung des Eingangskorbes. Das kann beispielsweise ein Refresh-Button sein, mit dem der User die Liste manuell aktualisieren kann, oder aber auch eine automatische Aktualisierung, die die Liste regelmäßig in einem bestimmten Intervall vollständig neu lädt. Ohne solche Maßnahmen würde der Eingangskorb nie einen aktuellen Stand anzeigen.

Steigende Komplexität

An ein System mit Push-Benachrichtigungen haben Anwender eine andere Erwartungshaltung als an „klassische“ Anwendungen. Das Buzzword „Push“ verspricht stets aktuelle Daten, alles in Echtzeit und ohne dass der Anwender irgendetwas tun muss. Doch das lässt sich in der Praxis leider nicht so einfach einhalten.
Erweitern wir das vorige Beispiel um eine langlaufende Operation, die anhand verschiedener Eingangskörbe Daten aggregiert und eine Statistik erstellt. In unserem Beispiel dauert diese Berechnung einige Zeit, weshalb wir uns entscheiden sie nur alle fünf Minuten laufen zu lassen und das Ergebnis danach per Push Notification an alle Clients zu senden. Die Eingangskörbe selbst werden also direkt und unmittelbar nach einer Änderung aktualisiert, die zugehörige Statistik jedoch in einem festgelegten Intervall. Das hat zur Folge, dass es aus Sicht des Anwenders zu Inkonsistenzen zwischen dem Eingangskorb und der Statistik kommen kann (welche somit praktisch schon wieder veraltet ist). Der Anwender ist es aber gewohnt, dass sich der Eingangskorb in Echtzeit aktualisiert, warum also nicht auch die davon abhängige Statistik? Daraus entsteht implizit die Anforderung, möglichst viele Daten per Push aktuell zu halten. Das bringt für die Anwender viele Vorteile, kann aber auch die Komplexität der Software stark erhöhen.

Der hausgemachte DDoS-Angriff

Besonders kritisch ist das Nachladen von Daten als Reaktion auf eine Push-Benachrichtigung (Push Notifications). Nehmen wir als Beispiel wieder einen Eingangskorb mit Aufgaben. Wenn ein neues Element im Eingangskorb landet sendet der Server eine Nachricht an alle verbundenen Clients, welche diesmal jedoch nur die ID des neu erstellten Objektes erhalten. Der Client kann nun die noch fehlenden Daten nachladen und dann dem Anwender anzeigen. Während der Entwicklung funktioniert dieser Mechanismus ohne Probleme. Innerhalb weniger Millisekunden wird die Anfrage des Clients bearbeitet und die Daten geladen. Was aber, wenn im produktiven Einsatz die Push-Benachrichtigung an hundert oder gar tausend Clients versendet wird? Die benachrichtigten Clients würden nun mehr oder weniger gleichzeitig versuchen die Daten nachzuladen und den Server so mit Anfragen überschwemmen. Die Last auf dem Server steigt plötzlich stark an, und das bei jeder Push-Benachrichtigung dieser Art. Ohne einen passenden Sicherheitsmechanismus sind Performanceprobleme sehr wahrscheinlich.
Wenn es sich vermeiden lässt, sollte man einfach auf das Nachladen von Informationen als Reaktion auf eine Push-Benachrichtigung verzichten. Wenn die Nachricht bereits alle vom Client benötigten Informationen mitliefert sind auch keine zusätzlichen Anfragen an den Server notwendig.

Fazit

Durch den Einsatz von Push-Benachrichtigungen (Push Notifications) können neue Informationen schnell vom Server zu allen verbundenen Clients übermittelt werden. Insbesondere für die Endbenutzer der Software bietet das enorme Vorteile, da sie stets mit aktuellen Daten arbeiten können. Allerdings steigt dadurch auch die Komplexität der Anwendung, sowohl auf Client- als auch auf Serverseite, und für bestimmte Konstellationen (wie beispielsweise Verbindungsverlust) sind separate Sicherheitsmaßnahmen erforderlich. Am Ende kann man dem Anwender aber ein System zur Verfügung stellen, welches sich schnell und dynamisch anfühlt.