Creazione di attività push

In questa pagina viene descritto come creare attività e inserirle in code in modalità push. Quando vuoi elaborare un'attività, devi creare un nuovo oggetto attività e posizionarlo in una coda. Puoi specificare esplicitamente il servizio e il gestore che elaborano l'attività e, facoltativamente, passare dati specifici dell'attività al gestore. Puoi anche ottimizzare la configurazione dell'attività, ad esempio pianificare un'ora futura in cui eseguire l'attività o limitare il numero di volte in cui vuoi che l'attività venga ritentata in caso di esito negativo.

Creazione di una nuova attività in corso...

Per creare e accodare un'attività, chiama la funzione taskqueue.add(). Il codice seguente crea un'attività che ha come target il servizio denominato worker e richiama il suo gestore impostando l'URL /update-counter:

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

In alternativa, puoi creare un oggetto Task e richiamare il relativo metodo add().

Specificare il servizio worker

Quando un'attività viene estratta 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 eseguirà 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/un'istanza in uno qualsiasi dei formati 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 il target quando crei l'attività. Puoi impostare il target in modo esplicito utilizzando il parametro target nella funzione taskqueue.add(). Vedi l'esempio riportato sopra.

  • Includi un'istruzione target quando definisci una coda in queue.yaml, come nella definizione di queue-blue. Tutte le attività aggiunte a una coda con un target utilizzeranno quel target, anche se all'attività è stato assegnato un target diverso al momento della creazione.

  • Se non viene specificata nessuna destinazione in base a uno dei due metodi precedenti, la destinazione dell'attività è la versione del servizio che la accoda. Tieni presente che se accoda un'attività dal servizio e dalla 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 non viene specificato alcun url, viene utilizzato l'URL predefinito /_ah/queue/[QUEUE_NAME], dove [QUEUE_NAME] è il nome della coda dell'attività.

Trasferimento dei 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.

Puoi anche utilizzare uno qualsiasi dei seguenti campi per aggiungere dati a un'attività:

  • payload, che consegna i dati delle attività nel corpo della richiesta HTTP.
  • params

Queste tre chiamate sono equivalenti:

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

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 un nome a un'attività utilizzando il parametro name. Un vantaggio di assegnare nomi alle tue attività è che le attività con nome 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 dopo il completamento o l'eliminazione dell'attività.

Tieni presente che la logica di deduplicazione introduce un significativo overhead delle prestazioni, determinando un aumento delle latenze e un potenziale aumento dei tassi di errore associati alle attività con nome. Questi costi possono essere aumentati notevolmente se i nomi delle attività sono sequenziali, ad esempio con i timestamp. Pertanto, se assegni nomi delle attività, 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 il nome può contenere lettere maiuscole e minuscole, numeri, trattini bassi e trattini.

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

Aggiunta delle attività in modo asincrono.

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

Poiché le operazioni di aggiunta di attività a code diverse non possono essere suddivise in batch, l'API Task Queue fornisce anche chiamate asincrone che consentono di aggiungere queste attività in parallelo, riducendo ulteriormente al minimo la latenza. Ciò è utile se stai creando un'applicazione estremamente sensibile alla latenza che deve eseguire diverse operazioni di aggiunta di attività a code diverse contemporaneamente.

Se vuoi effettuare chiamate asincrone a una coda di attività, utilizza i metodi asincroni forniti dalla classe Queue e da un oggetto RPC. Richiama get_result() sull'oggetto RPC restituito per forzare il completamento della richiesta. Quando aggiungi in modo asincrono attività a una transazione, devi chiamare get_result() sull'oggetto RPC prima di eseguire il commit della transazione per assicurarti che la richiesta sia terminata .

Accodamento delle attività nelle transazioni di Cloud Datastore

Puoi accodare un'attività come parte di una transazione Datastore, in modo che l'attività venga accodata (e garantita l'accodamento) solo se il commit della transazione è stato eseguito correttamente. Le attività aggiunte in una transazione vengono considerate parte della transazione 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:

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

Utilizzo della libreria di attività differite anziché di un servizio worker

Configurare un gestore per ogni singola attività (come descritto nelle sezioni precedenti) può essere complicato, così come serializzare e deserializzare argomenti complessi per l'attività, in particolare se vuoi eseguire molte attività diverse ma piccole che vuoi eseguire in coda. L'SDK Python include una libreria (google.appengine.ext.deferred) che espone una funzione semplice che ti consente di ignorare tutto il lavoro di configurazione di gestori di attività dedicati e di serializzare e deserializzare i parametri.

Per usare questa libreria, devi aggiungere l'deferred integrata a app.yaml. Per maggiori informazioni, consulta la sezione Gestori integrati del riferimento app.yaml.

Per utilizzare la libreria deferred, passa semplicemente la funzione e i suoi argomenti a 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)

La libreria deferred pacchettizza la chiamata di funzione e i relativi argomenti, quindi la aggiunge alla coda di attività. Quando l'attività viene eseguita, la libreria deferred esegue do_something_expensive("Hello, world!", 42, True).

Utilizzo delle attività in un'applicazione multi-tenant

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

Passaggi successivi