Creazione di attività push

In questa pagina viene descritto come creare le attività e come inserirle nelle code in modalità in push. Per elaborare un'attività, è necessario creare un nuovo oggetto di attività e metterlo in coda. Puoi specificare esplicitamente il servizio e il gestore che elaborano l'attività ed eventualmente trasferire i dati specifici dell'attività insieme al gestore. Puoi anche ottimizzare la configurazione dell'attività, ad esempio programmare un'ora futura in cui deve essere eseguita o limitare il numero di volte in cui vuoi che l'attività venga ripetuta.

Creazione di una nuova attività

Per creare e aggiungere in coda un'attività, ricevi un Queue utilizzando il QueueFactory e chiama il relativo metodo add(). Puoi ottenere una coda denominata nel file queue.xml utilizzando il metodo getQueue() della fabbrica; in alternativa, puoi ottenere la coda predefinita utilizzando getDefaultQueue(). Puoi chiamare il metodo add() di Queue con un'istanza TaskOptions (prodotto da TaskOptions.Builder) oppure puoi 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 espulsa dalla coda, il servizio coda attività lo invia a un servizio worker. Ogni attività ha un target e un url, che determinano quale servizio e gestore eseguirà l'attività.

target

Il target specifica il servizio che riceverà la richiesta HTTP per eseguire l'attività. È una stringa che specifica un servizio/versione/istanza in qualsiasi modulo canonico. I moduli più utilizzati sono:

    service
    version.service
    instance.version.service

La stringa di destinazione è anteposta al nome di dominio della tua app. Esistono tre modi per impostare il target per un'attività:

  • Dichiara il target quando crei l'attività. Puoi impostare esplicitamente il target 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 un target utilizzeranno tale target, anche se al momento dell'attività è stata assegnata una destinazione diversa.

  • Se non vengono specificati target secondo uno dei due metodi precedenti, la destinazione dell'attività corrisponde alla versione del servizio che li accoda. Tieni presente che se aggiungi un'attività al servizio e alla versione predefiniti in questo modo, e la versione predefinita cambia prima dell'esecuzione dell'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 è specificato l'URL predefinito /_ah/queue/[QUEUE_NAME], dove [QUEUE_NAME] è il nome della coda dell'attività.

Passaggio di dati al gestore

Puoi trasferire 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 ha metodi per aggiungere dati come payload della richiesta HTTP e come parametri che vengono aggiunti all'URL come parametri di ricerca.

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

Assegnazione di nomi a un'attività

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

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

Se assegni i tuoi nomi alle attività, tieni presente che la lunghezza massima del nome è di 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. Per la maggior parte degli scenari, le chiamate sincrone vanno bene. L'aggiunta di un'attività a una coda è di solito un'operazione veloce. Esiste una piccola percentuale di operazioni di aggiunta attività che possono richiedere molto più tempo, ma il tempo medio per aggiungere un'attività è inferiore a 5 ms.

Le operazioni di aggiunta di attività a code diverse non possono essere raggruppate, quindi l'API Task Queue offre anche chiamate asincrone che ti consentono di aggiungere queste attività in parallelo, riducendo ulteriormente la latenza. Ciò è utile se stai creando un'applicazione sensibile alla latenza estremamente necessaria che deve eseguire diverse operazioni di aggiunta attività in code diverse contemporaneamente.

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 in una transazione, devi chiamare get() su Future prima di confermare la transazione per garantire che la richiesta sia stata completata.

Inserimento di attività nelle transazioni di Cloud Datastore

Puoi aggiungere in coda un'attività come parte di una transazione Datastore, in modo che l'attività sia accodata (e garantita per essere accodata) se la transazione viene impegnata correttamente. Le attività aggiunte in una transazione sono considerate parte integrante della stessa e hanno lo stesso livello di isolamento e coerenza.

Un'applicazione non può inserire più di cinque attività transazionali in coda di attività durante una singola transazione. Le attività transazionali non devono avere nomi specificati dagli utenti.

Il seguente esempio di codice mostra come inserire attività transazionali in una coda 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é di un servizio worker

Configurare un gestore per ogni attività distinta (come descritto nelle sezioni precedenti) può essere complicato, così come serializzare e deserializzare gli argomenti complessi dell'attività, in particolare se devi eseguire numerose attività diverse ma piccole in coda. L'SDK Java include un'interfaccia denominata DeferredTask. Questa interfaccia ti consente di definire un'attività come un singolo metodo. Questa interfaccia utilizza la serializzazione Java per raggruppare un'unità di lavoro in una coda di attività. Un semplice ritorno da tale metodo è considerato un successo. Presentare eventuali eccezioni da quel metodo è considerato un errore.


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

Utilizzo delle attività in un'applicazione multi-tenant

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

Passaggi successivi