Transazioni NDB

Una transazione è un'operazione o un insieme di operazioni atomica, il che significa che le transazioni non sono mai parzialmente applicata. Tutte le operazioni nella transazione o nessuna di queste è applicata. Le transazioni hanno un durata massima di 60 secondi con una scadenza di inattività di 10 secondi tempo dopo 30 secondi.

Utilizzando l'API asincrona dell'NDB, un'applicazione può gestire più transazioni contemporaneamente se sono indipendenti. L'API sincrona offre un'API semplificata che utilizza Decoratore di @ndb.transactional(). La funzione decorata viene eseguita nel contesto della transazione.

@ndb.transactional
def insert_if_absent(note_key, note):
    fetch = note_key.get()
    if fetch is None:
        note.put()
        return True
    return False
note_key = ndb.Key(Note, note_title, parent=parent)
note = Note(key=note_key, content=note_text)
inserted = insert_if_absent(note_key, note)

Se la transazione "si blocca" con un'altra, fallisce; NDB automaticamente riprova più volte a eseguire queste transazioni non riuscite. La funzione può essere chiamata più volte se la transazione un nuovo tentativo. Esiste un limite (predefinito 3) al numero di nuovi tentativi tentato; se la transazione continua a non riuscire, NDB genera TransactionFailedError. Puoi modificare il nuovo tentativo conteggia passando retries=N al Decoratrice di transactional(). Un numero di nuovi tentativi pari a 0 indica che la transazione viene tentato una volta, ma non viene rieseguito se l'operazione non riesce; un numero di nuovi tentativi N significa che il tentativo di transazione potrebbe essere tentato per un totale di N+1 volte. Esempio:

@ndb.transactional(retries=1)
def insert_if_absent_2_retries(note_key, note):
    # do insert

Nelle transazioni sono consentite solo le query dei predecessori. Per impostazione predefinita, una transazione può funzionare solo con entità nella stesso gruppo di entità (entità le cui chiavi hanno lo stesso "predecessore").

Puoi specificare le transazioni tra gruppi ("XG") (che consentono fino a venticinque gruppi di entità), per superato xg=True:

@ndb.transactional(xg=True)
def insert_if_absent_xg(note_key, note):
    # do insert

Le transazioni tra gruppi operano su più gruppi di entità e si comportano come le transazioni di singoli gruppi, ma non avranno esito negativo se il codice tenta di aggiornare di entità da più gruppi di entità.

Se la funzione genera un'eccezione, la transazione viene immediatamente interrotta e NDB solleva nuovamente in modo che il codice chiamante la veda. È possibile forzare l'esito negativo di una transazione aumentando il livello ndb.Rollback eccezione (il la chiamata di funzione restituisce None in questo caso). Non esiste un meccanismo per forzare un nuovo tentativo.

Potresti avere una funzione che non sempre vuoi svolgere vengono eseguite in una transazione. Invece di decorare una tale funzione con @ndb.transactional, passalo come un callback funzione su ndb.transaction()

def insert_if_absent_sometimes(note_key, note):
    # do insert
inserted = ndb.transaction(lambda:
                           insert_if_absent_sometimes(note_key, note))

Per verificare se del codice è in esecuzione all'interno di una transazione, utilizza la in_transaction() personalizzata.

Puoi specificare il modo in cui un report funzione dovrebbe comportarsi se richiamata per codice già presente in una transazione. La Il decorator @ndb.non_transactional specifica che una funzione non deve essere eseguita in una transazione; se viene chiamato in una transazione, al di fuori della transazione. Il decorator di @ndb.transactional e la funzione ndb.transaction assumono una propagation argomento parola chiave. Ad esempio, se una funzione dovrebbe avviare una nuova transazione indipendente, decorandola in questo modo:

@ndb.transactional(propagation=ndb.TransactionOptions.INDEPENDENT)
def insert_if_absent_indep(note_key, note):
    # do insert

I tipi di propagazione sono elencati con gli altri Opzioni di contesto e Opzioni di transazione

Il comportamento delle transazioni e quello di memorizzazione nella cache di NDB possono combinarsi per confonderti se non si sa cosa sta succedendo. Se modifichi un'entità all'interno di una transazione, ma non hai ancora eseguito il commit la transazione, allora la cache di contesto di NDB ha il valore modificato il datastore sottostante ha ancora il valore non modificato.

Accodamento delle attività transazionali

Puoi accodare un'attività come parte di una transazione Datastore, che l'attività è in coda solo se il commit della transazione è andato a buon fine. Se la transazione non il commit dell'attività non viene accodata. Se viene eseguito il commit dell'attività, in coda. Una volta accodata, l'attività non verrà eseguita immediatamente, quindi l'attività non è minima della transazione. Tuttavia, una volta accodata, l'attività riproverà fino a quando non riesce. Applicabile a qualsiasi attività in coda durante una funzione decorata.

Le attività transazionali sono utili perché ti consentono di combinare di azioni non Datastore a una transazione che dipende dal transazione completata correttamente (ad esempio, l'invio di un'email per confermare acquisto). Puoi anche collegare le azioni Datastore alla transazione, ad esempio il commit delle modifiche in gruppi di entità al di fuori di transazione solo se va a buon fine.

Un'applicazione non può inserire più di cinque transazioni le tue attività nell'attività code durante una singola transazione. Le attività transazionali devono non hanno nomi specificati dall'utente.

from google.appengine.api import taskqueue
from google.appengine.ext import ndb
@ndb.transactional
def insert_if_absent_taskq(note_key, note):
    taskqueue.add(url=flask.url_for('taskq_worker'), transactional=True)
    # do insert