Push-Aufgaben erstellen

Auf dieser Seite wird gezeigt, 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 festlegen, an dem die Aufgabe ausgeführt werden soll, oder die Anzahl ihrer Wiederholungen bei Fehlversuchen beschränken.

Neue Aufgabe erstellen

Wenn Sie eine Aufgabe erstellen und in die Warteschlange stellen möchten, rufen Sie Queue mit QueueFactory ab und dann die zugehörige Methode add() auf. Sie können eine benannte Warteschlange abrufen, die in der Datei queue.xml angegeben ist. Dazu verwenden Sie die Methode getQueue() der Factory. Sie können aber auch mit getDefaultQueue() die Standardwarteschlange abrufen. Die Methode add() von Queue lässt sich mit einer von TaskOptions.Builder generiertenTaskOptions-Instanz aufrufen. Sie können die Methode auch ohne Argumente verwenden und damit eine Aufgabe mit den Standardoptionen für die Warteschlange erstellen.

import com.google.appengine.api.taskqueue.Queue;
import com.google.appengine.api.taskqueue.QueueFactory;
import com.google.appengine.api.taskqueue.TaskOptions;
Queue queue = QueueFactory.getDefaultQueue();
queue.add(TaskOptions.Builder.withUrl("/worker").param("key", key));

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 String „target“ 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 beim Erstellen einer Aufgabe angeben und dafür mit TaskOptions den Header Host festlegen:

    taskOptions.header("Host", versionHostname)
    

  • Fügen Sie eine target-Anweisung hinzu, wenn Sie eine Warteschlange in der Datei queue.xml definieren, genauso wie bei der Definition von queue-blue. Alle Aufgaben, die mit target in die Warteschlange eingefügt werden, verwenden dieses Ziel, auch wenn der Aufgabe zum Zeitpunkt ihres Erstellens ein anderes Ziel zugewiesen war.

  • Wenn kein Ziel mit einer der beiden vorherigen Methoden angegeben wurde, ist das Ziel der Aufgabe die Version des Dienstes, von der sie in die Warteschlange gestellt wurde. Wenn Sie auf diese Weise eine Aufgabe vom Standarddienst und der Standardversion 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

url wählt einen der Handler im Zieldienst aus, der die Aufgabe ausführen soll.

Dabei muss url mit einem der URL-Muster des Handlers im Zieldienst übereinstimmen. url kann Abfrageparameter enthalten, wenn in der Aufgabe die Methode GET oder PULL festgelegt wurde. Wenn kein url-Wert in der Standard-URL festgelegt ist, wird /_ah/queue/[QUEUE_NAME] verwendet. Dabei ist [QUEUE_NAME] der Name der Aufgabenwarteschlange.

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.

Der Konstruktor TaskOptions.Builder bietet Methoden zum Hinzufügen von Daten als Nutzlast der HTTP-Anfrage und als Parameter, die der URL als Abfrageparameter hinzugefügt werden.

params
Geben Sie "params" nicht an, wenn Sie die Methode POST zusammen mit einer Nutzlast verwenden oder wenn Sie bei Verwendung der Methode GET eine URL mit Abfrageparametern nutzen.

Aufgabe benennen

Wenn Sie eine neue Aufgabe erstellen, wird ihr von App Engine standardmäßig ein eindeutiger Name zugewiesen. Sie können einer Aufgabe jedoch mit dem Parameter name auch eigene 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.

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.

Zur Ausführung asynchroner Aufrufe für eine Aufgabenwarteschlange verwenden Sie die Klasse Queue. Rufen Sie get für das zurückgegebene Future-Argument auf, um die Ausführung der Anfrage zu erzwingen. Beim asynchronen Hinzufügen von Aufgaben in eine Transaktion sollten Sie vor dem Commit der Transaktion get() für Future aufrufen, um sicherzustellen, dass die Anforderung ausgeführt wurde.

Aufgaben in Cloud Datastore-Transaktionen in die Warteschlange stellen

Sie können eine Aufgabe als Teil einer Datastore-Transaktion in die Warteschlange stellen, sodass die Aufgabe dann – und nur dann – in die Warteschlange aufgenommen wird, wenn der Commit für die Transaktion erfolgreich ausgeführt wurde. Aufgaben, die Sie einer Transaktion hinzufügen, werden als Teil dieser Transaktion behandelt. Für sie gilt das gleiche Maß an Isolation und Konsistenz.

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 Beispielcode ist dargestellt, wie Sie Transaktionsaufgaben als Teil einer Datastore-Transaktion in eine Push-Warteschlange einreihen:

DatastoreService ds = DatastoreServiceFactory.getDatastoreService();
Queue queue = QueueFactory.getDefaultQueue();
try {
    Transaction txn = ds.beginTransaction();

    // ...

    queue.add(TaskOptions.Builder.withUrl("/path/to/my/worker"));

    // ...
    txn.commit();
} catch (DatastoreFailureException e) {
}

DeferredTasks anstelle eines Worker-Dienstes verwenden

Das Einrichten eines Handlers für jede einzelne Aufgabe (wie in den vorherigen Abschnitten beschrieben) kann mühsam sein, genau wie das Serialisieren und Deserialisieren komplexer Argumente für die Aufgabe. Dies trifft vor allem dann zu, wenn Sie viele verschiedene, aber kleine Aufgaben haben, die Sie in der Warteschlange ausführen möchten. Hier schafft das Java SDK mit einer Schnittstelle namens DeferredTask Abhilfe. Mit dieser Schnittstelle können Sie eine Aufgabe als eine einzelne Methode definieren. Diese Schnittstelle bedient sich der Java-Serialisierung, um eine Arbeitseinheit in einer Aufgabenwarteschlange zu bündeln. Eine einfache Rückgabe aus dieser Methode gilt als erfolgreiche Ausführung. Jede Ausnahme, die von dieser Methode ausgelöst wird, gilt als Fehler.


/** A hypothetical expensive operation we want to defer on a background task. */
public static class ExpensiveOperation implements DeferredTask {

  @Override
  public void run() {
    System.out.println("Doing an expensive operation...");
    // expensive operation to be backgrounded goes here
  }
}

/**
 * Basic demonstration of adding a deferred task.
 *
 * @param request servlet request
 * @param resp servlet response
 */
@Override
public void doGet(final HttpServletRequest request, final HttpServletResponse resp)
    throws IOException {
  // Add the task to the default queue.
  Queue queue = QueueFactory.getDefaultQueue();

  // Wait 5 seconds to run for demonstration purposes
  queue.add(
      TaskOptions.Builder.withPayload(new ExpensiveOperation())
          .etaMillis(System.currentTimeMillis() + DELAY_MS));

  resp.setContentType("text/plain");
  resp.getWriter().println("Task is backgrounded on queue!");
}

Mit Aufgaben in einer Anwendung mit Mehrinstanzenfähigkeit arbeiten

Push-Warteschlangen verwenden standardmäßig den Namespace, der zum Zeitpunkt der Aufgabenerstellung im Namespace-Manager festgelegt war. Wenn Ihre Anwendung die Mehrinstanzenfähigkeit nutzt, finden Sie entsprechende Informationen unter Namespaces Java 8 API.

Nächste Schritte