Wie können Sie Anwendungsteile kommunizieren lassen, wenn sie allemal über Netzwerke verteilt sind. Klar, irgendwie geht das mit WCF und Azure… Aber warum so kompliziert?
Stefan Lieser und ich verbringen gerade einige Tage in unserem jährlichen Clean Code Advisors Retreat, um das vergangene Jahr zu reflektieren und das nächste zu skizzieren. Neben viel Zeit zum Reden und Denken darf da aber natürlich auch die Programmierung nicht zu kurz kommen. Also haben wir uns eine Application Kata ausgedacht: AppZwitschern. Dabei geht es darum, Tweets mit einem Desktop (oder Mobile) Client zu erfassen und erst zu einem späteren Zeitpunkt zu versenden. Selbstverständlich muss der Client dafür nicht offen gehalten werden. Die terminierte Versendung übernimmt ein Server.
Das ist eine schöne Aufgabe, in der wir die neue Flow Runtime NPantaRhei einsetzen. Macht Spaß, funktioniert gut. Darüber hinaus kommen einige Technologien zum Einsatz, z.B. Twitter, bit.ly, NCron und auch eine Kommunikationstechnologie. Die Clients müssen ja dem Server die Tweets zur späteren Versendung schicken.
Zuerst haben wir dafür Amazon SQS benutzt. Das ist Cloud Queue-Service. Der funktioniert. Unsere verteilte App zwitschert damit verlässlich und skalierbar. Alle Clients schreiben in dieselbe SQS Queue. Und beliebig viele Server-Instanzen verarbeiten die Versandaufträge. Perfektes scale-out.
Aber Amazon SQS hat einen recht umständlichen API. Und interessanterweise sichert SQS nicht zu, die Nachrichten in einer Warteschlange in der Reihenfolge abzuliefern (dequeue), in welcher sie eingestellt wurden (enqueue). Das ist zwar für unser Szenario nicht so wichtig, dennoch irgendwie merkwürdig. Lohnt sich da wirklich eine nähere Beschäftigung mit diesem Service?
Auch wenn wir für AppZwitschern nicht mehr Leistung brauchen, habe ich dann aber mal geschaut, ob es Alternativen gibt. Und tatsächlich, die gibt es. Hängengeblieben bin ich ganz schnell bei IronMQ von iron.io.
Attraktiv war deren Anspruch an Einfachheit:
- Einfache Anmeldung ohne Kreditkartenangabe, da 250.000 Nachrichten pro Monat ohnehin frei sind. Sie wollen es Interessenten also leicht machen, IronMQ auszuprobieren.
- Einfacher API auf für .NET. Der ist als Quelle bei github zu finden: iron_mq_dotnet. Unter downloads findet sich allerdings auch eine binäre Version.
Und IronMQ bietet, was SQS nicht hat: echte FIFO-Semantik.
Also habe ich alternativ zu unseren SQS-Operationen für die AppZwitschern-Flows welche für IronMQ aufgesetzt. Das war in 20 Minuten gemacht. Hier unser IronMQ-Adapter, der simples Enqueue und Dequeue so anbietet, das es leicht bei der Flow Runtime zu registrieren ist:
public class IronMQOperations
{
private readonly Client _client;
private readonly Queue _queue;
public IronMQOperations(string queueName, string projectId, string token)
{
_client = new Client(projectId, token);
_queue = _client.queue(queueName);
}
public void Enqueue(string data)
{
_queue.push(data);
}
public void Dequeue(Action<string> onDataReceived)
{
do
{
var msg = _queue.get();
if (msg == null) break;
onDataReceived(msg.Body);
_queue.deleteMessage(msg);
} while (true);
onDataReceived(null);
}
}
Ich würde sagen, einfacher gehts kaum. Mit den paar Zeilen ist eine verlässliche Kommunikation via Cloud möglich. Die braucht ihre Zeit; Performance wie mit TCP im lokalen Netz ist da nicht zu erwarten. Aber das spielt für unser Szenario und viele andere keine Rolle. Es geht darum, serverseitig skalieren zu können.
Der SQS-Adapter hat knapp doppelt soviele LOC – und bietet eben nicht das, was man von einer Queue erwartet.
Nun bin ich gespannt auf die .NET Bindings für die anderen iron.io Dienste: den Key-Value-Store (Cache) und serverseitige Prozesse (Worker). Einstweilen habe ich in meinem Köcher einen no-brainer für die Verteilung von Arbeitspaketen.
PS: Der Support bei iron.io ist gut. Ich habe ein paar Fragen gehabt und den angebotenen Live Chat benutzt. Da war zu jeder Tageszeit jemand zu erreichen, der entweder Auskunft geben konnte oder dafür gesorgt hat, dass mir später geholfen wurde. I like that.