Push-Aufgaben erstellen

Auf dieser Seite wird beschrieben, wie Sie Aufgaben erstellen und in Push-Warteschlangen einfügen. Wenn Sie eine Aufgabe verarbeiten möchten, müssen Sie ein neues Aufgabenobjekt erstellen und in eine Warteschlange stellen. Sie können den Dienst und den Handler, mit denen die Aufgabe verarbeitet wird, ausdrücklich angeben und optional aufgabenspezifische Daten an den Handler weiterleiten. Außerdem können Sie für die Konfiguration der Aufgabe Feineinstellungen vornehmen, z. B. einen Zeitpunkt in der Zukunft angeben, zu dem die Aufgabe ausgeführt werden soll, oder die Anzahl ihrer Wiederholungen im Fall von Fehlversuchen beschränken.

Neue Aufgaben erstellen

Rufen Sie die Funktion taskqueue.add() auf, um eine Aufgabe zu erstellen und in eine Warteschlange einzufügen. Mit dem folgenden Code erstellen Sie eine Aufgabe, die einen Dienst mit dem Namen worker als Ziel hat und ihren Handler durch Festlegen der URL /update-counter aufruft:

class EnqueueTaskHandler(webapp2.RequestHandler):
    def post(self):
        amount = int(self.request.get('amount'))

        task = taskqueue.add(
            url='/update_counter',
            target='worker',
            params={'amount': amount})

        self.response.write(
            'Task {} enqueued, ETA {}.'.format(task.name, task.eta))

Alternativ können Sie ein Objekt vom Typ Task erstellen und dessen Methode add() aufrufen.

Worker-Dienst angeben

Wenn eine Aufgabe in der Warteschlange an der Reihe ist, wird sie vom Dienst für Aufgabenwarteschlangen an einen Worker-Dienst gesendet. Jede Aufgabe verfügt über ein Ziel und eine URL, mit denen bestimmt wird, von welchem Dienst und Handler die Aufgabe letztendlich ausgeführt wird.

target

Mit dem Ziel wird der Dienst angegeben, der die HTTP-Anfrage zur Ausführung der Aufgabe erhält. Dabei handelt es sich um einen String, mit dem ein Dienst, eine Version oder eine Instanz in einem der kanonischen Formate angegeben wird. Am häufigsten werden folgende Formate verwendet:

    service
    version.service
    instance.version.service

Der Zielstring wird dem Domainnamen Ihrer Anwendung vorangestellt. Es gibt drei Möglichkeiten, um das Ziel für eine Aufgabe festzulegen:

  • Deklarieren Sie das Ziel beim Erstellen der Aufgabe. Sie können das Ziel explizit mit dem Parameter target in der Funktion taskqueue.add() festlegen. Sehen Sie sich dazu das Beispiel oben an.

  • Fügen Sie die Anweisung target ein, wenn Sie wie bei der Definition von queue-blue eine Warteschlange in der Datei queue.yaml festlegen. Dieses Ziel wird für alle Aufgaben, die einer Warteschlange mit einem target hinzugefügt wurden, übernommen, auch wenn der Aufgabe bei ihrer Erstellung ein anderes Ziel zugewiesen wurde.

  • Wenn mit einer der beiden vorherigen Methoden kein Ziel angegeben wurde, ist das Ziel der Aufgabe die Version des Dienstes, von der sie in die Warteschlange gestellt wurde. Wenn Sie eine Aufgabe vom Standarddienst und der Standardversion auf diese Weise in die Warteschlange einfügen und sich die Standardversion vor Ausführung der Aufgabe ändert, wird die Aufgabe in der neuen Standardversion ausgeführt.

url

Von der url wird einer der Handler im Zieldienst ausgewählt, der die Aufgabe dann ausführt.

Die url sollte einem URL-Muster des Handlers im Zieldienst entsprechen. Die url kann Abfrageparameter enthalten, sofern die in der Aufgabe angegebene Methode GET oder PULL ist. Wenn keine url angegeben ist, wird die Standard-URL /_ah/queue/[QUEUE_NAME] verwendet, wobei [QUEUE_NAME] der Name der Warteschlange der Aufgabe ist.

Daten an den Handler übergeben

Sie können Daten als Abfrageparameter an den Handler in der URL der Aufgabe übergeben. Voraussetzung ist, dass in der Aufgabe die Methode GET oder PULL angegeben wurde.

Sie können auch eines der folgenden Felder verwenden, um Daten zu einer Aufgabe hinzuzufügen:

  • payload, womit Aufgabendaten im Textkörper der HTTP-Anfrage bereitgestellt werden
  • params

Folgende drei Aufrufe sind äquivalent:

taskqueue.add(method=GET, url='/update-counter?key=blue', target='worker')
taskqueue.add(url='/update-counter', params={'key': 'blue'}, target='worker')
taskqueue.add(url='/update-counter', payload="{'key': 'blue'}", target='worker')

Aufgaben benennen

Wenn Sie eine neue Aufgabe erstellen, wird ihr von App Engine standardmäßig ein eindeutiger Name zugewiesen. Über den Parameter name können Sie einer Aufgabe jedoch auch einen eigenen Namen zuweisen. Die Zuweisung eigener Aufgabennamen hat den Vorteil, dass benannte Aufgaben dedupliziert werden. So können Sie anhand von Aufgabennamen gewährleisten, dass eine Aufgabe nur einmal hinzugefügt wird. Die Deduplizierung wird noch neun Tage fortgeführt, nachdem die Aufgabe abgeschlossen oder gelöscht wurde.

Dabei ist zu beachten, dass die Deduplizierungslogik zu signifikanten Leistungseinbußen führen und die Latenzen und unter Umständen auch die Fehlerraten im Zusammenhang mit benannten Aufgaben erhöhen kann. Bei sequenziellen Aufgabennamen, beispielsweise mit Zeitstempeln, können diese Einbußen noch erheblich höher ausfallen. Wir empfehlen daher, beim Zuweisen eigener Namen ein wohlüberlegtes Präfix für Aufgabennamen zu verwenden, beispielsweise einen Hashwert des Inhalts.

Wenn Sie Aufgaben eigene Namen zuweisen, dürfen Sie die maximale Namenslänge von 500 Zeichen nicht überschreiten. Der Name kann Groß- und Kleinbuchstaben, Zahlen sowie Unter- und Bindestriche enthalten.

taskqueue.add(url='/url/path', name='first-try')

Aufgaben asynchron hinzufügen

Standardmäßig sind die Aufrufe, die Aufgaben zu Warteschlangen hinzufügen, synchron. In den meisten Szenarien funktionieren synchrone Aufrufe problemlos. Aufgaben können normalerweise schnell in eine Warteschlange gestellt werden. Ein kleiner Prozentsatz der Vorgänge, mit denen Aufgaben hinzugefügt werden, kann deutlich länger dauern. Durchschnittlich dauert es jedoch weniger als 5 ms, eine Aufgabe hinzuzufügen.

Vorgänge zum Einstellen von Aufgaben in verschiedene Warteschlangen können nicht im Batch-Modus ausgeführt werden, deshalb ermöglicht die Task Queue API auch asynchrone Aufrufe, über die Sie diese Aufgaben parallel einstellen und somit die Latenz weiter verringern können. Dies ist hilfreich, wenn Sie eine sehr latenzempfindliche Anwendung erstellen, die mehrere Vorgänge zum Einstellen von Aufgaben in verschiedene Warteschlangen gleichzeitig ausführen muss.

Verwenden Sie die asynchronen Methoden der Klasse Queue und ein RPC-Objekt, um asynchrone Aufrufe an eine Aufgabenwarteschlange auszuführen. Rufen Sie für das zurückgegebene RPC-Objekt die Methode get_result() auf, um den Abschluss der Anfrage zu erzwingen. Wenn Sie Aufgaben asynchron in einer Transaktion hinzufügen, sollten Sie vor dem Commit der Transaktion die Methode get_result() für das Objekt vom Typ RPC aufrufen. So können Sie sicher sein, dass die Anfrage abgeschlossen wurde.

Aufgaben in Cloud Datastore-Transaktionen in die Warteschlange stellen

Sie können eine Aufgabe als Teil einer Cloud Datastore-Transaktion in die Warteschlange einfügen, sodass die Aufgabe nur dann garantiert in die Warteschlange aufgenommen wird, wenn der Commit der Transaktion erfolgreich durchgeführt wurde. Aufgaben, die Sie im Rahmen einer Transaktion hinzufügen, werden als Teil dieser Transaktion behandelt. Sie weisen das gleiche Maß an Isolation und Konsistenz auf.

Eine Anwendung kann während einer einzelnen Transaktion nicht mehr als fünf Transaktionsaufgaben in Aufgabenwarteschlangen einfügen. Transaktionsaufgaben dürfen keine vom Nutzer angegebenen Namen haben.

Im folgenden Codebeispiel wird veranschaulicht, wie Transaktionsaufgaben als Teil einer Cloud Datastore-Transaktion in eine Push-Warteschlange eingefügt werden:

from google.appengine.api import taskqueue
from google.appengine.ext import ndb

@ndb.transactional
def do_something_in_transaction():
  taskqueue.add(url='/path/to/my/worker', transactional=True)
  #...

do_something_in_transaction()

Bibliothek zurückgestellter Aufgaben anstelle eines Worker-Dienstes verwenden

Das Einrichten eines Handlers für jede einzelne Aufgabe (wie in den vorherigen Abschnitten beschrieben) kann genau wie das Serialisieren und Deserialisieren komplexer Argumente für die Aufgabe mühsam sein. Dies trifft vor allem dann zu, wenn Sie viele verschiedene, aber kleine Aufgaben haben, die Sie in der Warteschlange ausführen möchten. Das Python SDK enthält eine Bibliothek (google.appengine.ext.deferred), die eine einfache Funktion bereitstellt, mit der Sie die aufwendige Einrichtung dedizierter Aufgaben-Handler und das Serialisieren und Deserialisieren der Parameter umgehen können.

Wenn Sie diese Bibliothek nutzen möchten, müssen Sie der Datei app.yaml den integrierten Handler deferred hinzufügen. Weitere Informationen finden Sie in der Referenz zu app.yaml im Abschnitt zu integrierten Handlern.

Zur Verwendung der Bibliothek deferred übergeben Sie einfach die Funktion und ihre Argumente an deferred.defer():

import logging

from google.appengine.ext import deferred

def do_something_expensive(a, b, c=None):
    logging.info("Doing something expensive!")
    # Do your work here

# Somewhere else
deferred.defer(do_something_expensive, "Hello, world!", 42, True)

Die Bibliothek deferred bündelt Ihren Funktionsaufruf und die zugehörigen Argumente und fügt sie der Aufgabenwarteschlange hinzu. Wenn die Aufgabe ausgeführt wird, führt die Bibliothek deferred den Code do_something_expensive("Hello, world!", 42, True) aus.

Weitere Informationen zum Verwenden der Bibliothek deferred in Python finden Sie im Artikel zum Ausführen von Aufgaben im Hintergrund mit der Deferred-Bibliothek.

In mehrinstanzenfähigen Anwendungen mit Aufgaben arbeiten

Push-Warteschlangen verwenden standardmäßig den Namespace, der zum Zeitpunkt der Aufgabenerstellung im Namespace-Manager festgelegt wurde. Wenn Ihre Anwendung die Mehrinstanzenfähigkeit nutzt, lesen Sie die Informationen zur Namespaces Python 2 API.

Weitere Informationen

Hat Ihnen diese Seite weitergeholfen? Teilen Sie uns Ihr Feedback mit:

Feedback geben zu...

App Engine-Standardumgebung für Python 2