Cloud Intelligence™Cloud Intelligence™

Cloud Intelligence™

Emulator für Cloud Tasks gesucht?

By Joshua FoxAug 10, 20205 min read

Diese Seite ist auch in English, Español, Français, Italiano, 日本語 und Português verfügbar.

Ein schlanker Tasks-Emulator, der Deployment und Debugging deutlich vereinfacht.

Wer eine Anwendung mit Cloud Tasks entwickelt – etwa eine Web-App –, möchte nachvollziehen können, was mit den Tasks geschieht: wie sie geplant, zugestellt und vom Task-Handler verarbeitet werden. Doch obwohl ein passender Emulator immer wieder gewünscht wird, bietet Google für Cloud Tasks bislang keinen an – anders als für Datastore oder PubSub.

Mein neuer Cloud Tasks In-Process Emulator in Python schließt diese Lücke. Wer es eilig hat und direkt loslegen möchte, springt am besten gleich zum Abschnitt "Quick Start" weiter unten.

Wege zur Entwicklung mit Cloud Tasks

Sie haben vier Optionen:

  1. Den echten Cloud-Tasks-Dienst verwenden.
  2. Einen lokalen Emulator nutzen, der dieselbe HTTP-Schnittstelle wie Cloud Tasks bereitstellt.
  3. Ganz darauf verzichten: Tasks gar nicht behandeln. Die Erstellung kann stillschweigend fehlschlagen, oder Sie feuern Tasks ohne definierten Handler ab.
  4. Einen In-Process-Emulator einsetzen. In der Entwicklung wird er injiziert, in produktiven Systemen läuft eine Implementierung auf Basis von Cloud Tasks.

Meine Empfehlung:

  • In-Process-Emulator für die Entwicklung
  • Echtes Cloud Tasks für Integrationstests in der Cloud
  • Cloud Tasks aus Unit-Tests heraushalten.

Sehen wir uns an, warum.

Die Vorteile von In-Process

Debugging

In der Entwicklung wollen Sie wissen, wo sich jeder Task befindet und was er enthält. Läuft der Emulator In-Process, klappt das direkt im Debugger – Sie pausieren die Queue und prüfen die Werte.

Schlicht ist gut

Der Code dieses Emulators ist bewusst minimal gehalten und unterstützt nur das Erstellen und Verarbeiten von Tasks. Das hat einen Grund: Eine kleinere Codebasis (hier unter 100 Zeilen) ist beim Debuggen klar im Vorteil.

Bei einem Alpha-Produkt – und alle Cloud-Tasks-Emulatoren, dieser eingeschlossen, sind im Alpha-Stadium – ist es zudem beruhigend, den gesamten Code unmittelbar im Zugriff zu haben, um schnell debuggen oder anpassen zu können.

Für mehr Funktionsumfang und realistischere Tests würde ich auf das echte Cloud Tasks in einer in der Cloud bereitgestellten Anwendung setzen.

Einfache Handhabung

Andere Cloud-Tasks-Emulatoren wie der gcloud-tasks-emulator von Potato London oder der cloud-tasks-emulator von Aert van de Hulsbeek laufen auf localhost und haben den Vorteil, dieselbe API wie der Cloud-Dienst bereitzustellen; Sie tauschen lediglich den Endpoint aus. Außerdem kann Code in beliebigen Sprachen diese Emulatoren ansprechen – beim In-Process-Emulator ist das nicht möglich.

Allerdings bringt ein zusätzlicher Prozess auch Mehraufwand mit sich: Sie müssen ihn vor jeder Entwicklungssitzung starten und im Auge behalten, ob er abgestürzt oder eingefroren ist. Und auch wenn sich solche Emulatoren im Debugger starten und debuggen lassen, gehört das in der Regel nicht zum üblichen Entwicklungs-Workflow.

Tasks nicht aus den Augen verlieren

Sie können Tasks an Cloud Tasks abschicken und nie verarbeiten – oder das Erstellen einfach stillschweigend fehlschlagen lassen. Das funktioniert gut, wenn der eigentliche Entwicklungs-Flow das Verarbeiten der Tasks gar nicht umfasst, etwa wenn diese in einem separaten Microservice landen, für den ein anderes Team verantwortlich ist. Auch für Unit-Tests passt dieser Ansatz, denn diese werden in der Regel nicht für verteilte asynchrone Prozesse genutzt – das ist die Aufgabe von Integrationstests.

Wer aber sehen möchte, was tatsächlich mit den Tasks passiert und wie der Callback sie verarbeitet, kommt um einen Emulator nicht herum.

Mit oder ohne Cloud entwickeln

Für einen vollständigen End-to-End-Flow können Sie auch das echte Cloud Tasks auf Ihrem Entwicklungsrechner verwenden und erhalten so dieselbe API und Funktionalität wie im produktiven System. Für Integrationstests in der Cloud ist das ideal.

Auf dem Entwicklungsrechner brauchen Sie dafür allerdings durchgehend eine Netzwerkverbindung; außerdem müssen Sie einen Proxy wie ngrok einrichten, damit die Google Cloud Platform Ihre lokale Maschine erreicht (wie hier beschrieben). Die echte Cloud-Tasks-API setzt zudem echte Queues voraus – Sie brauchen also entweder ein eigenes Google-Cloud-Projekt oder müssen die Queues so verwalten, dass jeder Entwickler einen eigenen Satz erhält.

Das bedeutet auch: Schon beim Debuggen einfacher Abläufe auf Ihrem Entwicklungsrechner landen Sie immer wieder in der Cloud Console, um an mehr Informationen zu kommen. Ich spare mir das Setup lieber und halte das Debugging in meinem Prozess.

Funktionen und Einschränkungen

Das Projekt unterstützt die Funktionalität, die in der Entwicklung typischerweise gebraucht wird: einen Task erstellen und ihn anschließend in einem Callback verarbeiten.

Wegen der bereits erwähnten Vorliebe für Schlichtheit fehlen jedoch andere Features, etwa:

  • Queue-Management, also Erstellen, Löschen, Leeren, Pausieren und Fortsetzen von Queues. (Beim Erstellen eines Tasks wird die Queue automatisch angelegt, sofern sie noch nicht existiert.)
  • Rate-Limits und Retries.
  • Deduplizierung und Löschen von Tasks.

Wenn Sie sich neue Funktionen wünschen (und diese einfach genug sind, um den Komplexitätszuwachs zu rechtfertigen), freue ich mich über Pull Requests oder Issues auf GitHub.

Quick Start

Um den Emulator zu nutzen, kopieren Sie einfach emulator.py in Ihre Codebasis – Sie können den Code der Datei sogar direkt von GitHub übernehmen – und schon kann es losgehen.

Erstellen Sie ein Emulator-Objekt und übergeben Sie eine Callback-Funktion, die die Payloads der erzeugten Tasks erhält. Um Tasks zu versenden, rufen Sie anschließend die Methode Emulator.create_task auf. Den Namen der Queue und den geplanten Auslieferungszeitpunkt legen Sie dabei selbst fest.

Anwendungsbeispiel

Im Projekt sehen Sie emulator.py in einer einfachen Webapp im Einsatz. Starten Sie sie über local_server.py. Rufen Sie anschließend http://127.0.0.1:8080 auf (oder klicken Sie einfach auf den Link in der Konsole) – damit wird ein Task erstellt. Drei Sekunden später wird der Task planmäßig verarbeitet und auf der Standardausgabe ausgegeben.

Wer es mit der Code-Hygiene genau nimmt und den Produktivcode frei vom Emulator halten möchte – also emulator.py beim Deployment auslässt –, findet in diesem Beispiel die passende Vorlage. In local_server.py, das in der Entwicklung zum Einsatz kommt, injizieren wir einen Emulator. In einem deployten Server hingegen, in dem kein solcher Emulator injiziert wird, entsteht ein neuer CloudTasksAccessor, der die echte Cloud-Tasks-API aufruft. So bleibt der Servercode (main.py) frei von jeglichem Emulator-Code.