Creazione di attività push

In questa pagina viene descritto come creare attività e inserirle nelle code in modalità push. Quando vuoi elaborare un'attività, devi creare un nuovo oggetto attività e posizionarlo su una coda. Puoi specificare esplicitamente il servizio e il gestore che elaborano l'attività e, facoltativamente, passare al gestore i dati specifici dell'attività. Puoi anche perfezionare la configurazione dell'attività, ad esempio pianificare un momento futuro in cui deve essere eseguita o limitare il numero di tentativi dell'attività in caso di errore.

Creazione di una nuova attività

Per creare e accodare un'attività, ottieni un Queue utilizzando QueueFactory e chiama il relativo metodo add(). Puoi ottenere una coda denominata specificata nel file queue.xml utilizzando il metodo getQueue() del produttore oppure puoi ottenere la coda predefinita utilizzando getDefaultQueue(). Puoi chiamare il metodo add() di Queue con un'istanza TaskOptions (prodotta da TaskOptions.Builder) oppure chiamarlo senza argomenti per creare un'attività con le opzioni predefinite per la coda.

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));

Specifica del servizio worker

Quando un'attività viene scollegata dalla coda, il servizio coda di attività la invia a un servizio worker. Ogni attività ha un target e un URL, che determinano quale servizio e gestore eseguiranno l'attività.

target

La destinazione specifica il servizio che riceverà la richiesta HTTP per eseguire l'attività. È una stringa che specifica un servizio, una versione o un'istanza in uno qualsiasi dei moduli canonici. I moduli più utilizzati sono:

    service
    version.service
    instance.version.service

La stringa di destinazione è anteposta al nome di dominio dell'app. Esistono tre modi per impostare la destinazione per un'attività:

  • Dichiara la destinazione quando crei l'attività. Puoi impostare la destinazione in modo esplicito durante la creazione dell'attività impostando l'intestazione Host utilizzando TaskOptions:

    taskOptions.header("Host", versionHostname)
    

  • Includi un'istruzione target quando definisci una coda in queue.xml, come nella definizione di queue-blue. Tutte le attività aggiunte a una coda con target utilizzeranno quella destinazione, anche se all'attività è stata assegnata una destinazione diversa al momento della creazione.

  • Se non viene specificata alcuna destinazione in base a uno dei due metodi precedenti, la destinazione dell'attività sarà la versione del servizio che la mette in coda. Tieni presente che se accoda un'attività dal servizio e dalla versione predefiniti in questo modo e la versione predefinita cambia prima dell'esecuzione, l'attività verrà eseguita nella nuova versione predefinita.

url

url seleziona uno dei gestori nel servizio di destinazione, che eseguirà l'attività.

url deve corrispondere a uno dei pattern URL del gestore nel servizio di destinazione. url può includere parametri di ricerca se il metodo specificato nell'attività è GET o PULL. Se url non viene specificato, viene utilizzato l'URL predefinito /_ah/queue/[QUEUE_NAME], dove [QUEUE_NAME] è il nome della coda dell'attività.

Passaggio di dati al gestore

Puoi passare i dati al gestore come parametri di ricerca nell'URL dell'attività, ma solo se il metodo specificato nell'attività è GET o PULL.

Il costruttore TaskOptions.Builder offre metodi per aggiungere dati come payload della richiesta HTTP e come parametri, che vengono aggiunti all'URL come parametri di query.

params
Non specificare i parametri se utilizzi il metodo POST insieme a un payload o se usi il metodo GET e hai incluso un URL con parametri di query.

Assegnare un nome a un'attività

Quando crei una nuova attività, App Engine assegna all'attività un nome univoco per impostazione predefinita. Tuttavia, puoi assegnare il tuo nome a un'attività utilizzando il parametro name. Un vantaggio dell'assegnazione di nomi personalizzati alle attività è che le attività denominate vengono deduplicate, il che significa che puoi utilizzare i nomi per garantire che un'attività venga aggiunta una sola volta. La deduplicazione continua per 9 giorni dopo il completamento o l'eliminazione dell'attività.

Tieni presente che la logica di deduplicazione introduce un overhead significativo delle prestazioni, con un conseguente aumento delle latenze e dei tassi di errore associati alle attività con nome. Questi costi possono essere aumentati notevolmente se i nomi delle attività sono sequenziali, ad esempio per i timestamp. Se assegni nomi personalizzati, ti consigliamo di utilizzare un prefisso ben distribuito per i nomi delle attività, ad esempio un hash dei contenuti.

Se assegni nomi personalizzati alle attività, tieni presente che la lunghezza massima del nome è 500 caratteri e che può contenere lettere maiuscole e minuscole, numeri trattini bassi e trattini.

Aggiunta di attività in modo asincrono

Per impostazione predefinita, le chiamate che aggiungono attività alle code sono sincrone. Nella maggior parte degli scenari, le chiamate sincrone funzionano correttamente. L'aggiunta di un'attività a una coda in genere è un'operazione rapida. Una piccola percentuale di operazioni di aggiunta delle attività può richiedere molto più tempo, ma il tempo medio per aggiungere un'attività è inferiore a 5 ms.

L'aggiunta di operazioni di attività a code diverse non può essere raggruppata in batch. Di conseguenza, l'API Task Queue fornisce anche chiamate asincrone che offrono la possibilità di aggiungere queste attività in parallelo, riducendo ulteriormente la latenza. Ciò è utile se stai creando un'applicazione sensibile alla latenza estremamente elevata che deve eseguire contemporaneamente diverse operazioni di aggiunta di attività a code diverse.

Se vuoi effettuare chiamate asincrone a una coda di attività, utilizza i metodi asincroni forniti dalla classe Queue. Chiama get sul Future restituito per forzare il completamento della richiesta. Quando aggiungi attività in modo asincrono a una transazione, devi chiamare get() su Future prima di eseguire il commit della transazione per assicurarti che la richiesta sia stata completata.

Coda delle attività nelle transazioni di Cloud Datastore

Puoi accodare un'attività nell'ambito di una transazione Datastore, in modo che l'attività venga accodata solo in coda e se il commit della transazione viene eseguito correttamente. Le attività aggiunte in una transazione sono considerate parte della stessa e hanno lo stesso livello di isolamento e coerenza.

Un'applicazione non può inserire più di cinque attività transazionali nelle code di attività durante una singola transazione. Le attività transazionali non devono avere nomi specificati dall'utente.

Il seguente esempio di codice mostra come inserire attività transazionali in una coda in modalità push come parte di una transazione Datastore:

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) {
}

Utilizzo di DeferredTasks anziché un servizio worker

Impostare un gestore per ogni attività distinta (come descritto nelle sezioni precedenti) può essere complicato, così come la serializzazione e la deserializzazione di argomenti complessi dell'attività, in particolare se ci sono molte attività diverse ma piccole che vuoi eseguire nella coda. L'SDK Java include un'interfaccia denominata DeferredTask. Questa interfaccia consente di definire un'attività come metodo singolo. Questa interfaccia utilizza la serializzazione Java per pacchettizzare un'unità di lavoro in una coda di attività. Un semplice ritorno da questo metodo è considerato un successo. Eventuali eccezioni a questo metodo sono considerate non riuscite.


/** 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!");
}

Lavorare con le attività in un'applicazione multi-tenant

Per impostazione predefinita, le code in modalità push utilizzano lo spazio dei nomi attuale impostato nello spazio dei nomi al momento della creazione dell'attività. Se l'applicazione utilizza la multitenancy, consulta API Java 8 di Namespaces.

Passaggi successivi