2012-09-04 8 views
10

Ho un metodo POST che chiama alcuni tasklet. Queste tasklet hanno rendimenti in esse, e ho un po 'di x.put_async() nel mio codice. Quindi non voglio che ritorni prima che tutte le cose asincrone siano fatte. Così ho decorato tutti i miei tasklet, che sono solo piccole funzioni con @ndb.tasklet. Inoltre, sulla parte superiore del mio metodo POST, ho:Utilizzo di @ ndb.tasklet o @ ndb.synctasklet in Google App Engine

@ndb.toplevel 
def post(self): 

Tuttavia, nel documentation afferma:

Ma se un metodo di gestore utilizza rendimento, tale metodo deve ancora essere avvolto in un altro decoratore, @ ndb.synctasklet; altrimenti, interromperà l'esecuzione alla resa e non terminerà.

In effetti il ​​mio metodo ha una resa. È già stato inserito in @ ndb.tasklet. Lo sostituisco con @ ndb.synctasklet o li uso entrambi (se sì, come utilizzerei entrambi)?

Inoltre, vedere this thread che ha una certa rilevanza. Anch'io ho notato un problema in cui la mia richiesta sarebbe tornata senza alcun output, ma non è riproducibile. Succede ogni 15 minuti circa di uso costante. Avevo solo app = ndb.toplevel(webapp2.WSGIApplication([..]), ma ora ho aggiunto @ndb.toplevel ai metodi principali POST, ma il problema persiste ancora.

Devo inserire @ndb.tasklet sopra i metodi che hanno solo put_async()? (Dovrei metterlo sopra ogni metodo solo per sicurezza? Quali sono gli aspetti negativi di questo?)

risposta

10

Per quanto riguarda il gestore e l'utilizzo di @ ndb.toplevel e @ ndb.synctasklet: Il modo in cui ho capito che era è necessario utilizzare sia @ ndb.synctasklet che @ ndb.toplevel sul gestore. Tutte le sotto-attività richiedono solo il decoratore @ ndb.tasklet. per esempio.

class Foo(ndb.Model): 
    name = ndb.StringProperty() 

    @ndb.tasklet 
    def my_async(self): 
     .... 
     #do something else that yields 
     raise ndb.Return("some result") 


@ndb.toplevel 
@ndb.synctasklet 
def post(self): 
    foo = Foo(name="baz") 
    yield foo.put_async() 
    yield foo.my_async() 
    .... 

Tuttavia. guardando il source, sembra che @ ndb.toplevel è in realtà uno synctasklet comunque:

def toplevel(func): 
    """A sync tasklet that sets a fresh default Context. 

    Use this for toplevel view functions such as 
    webapp.RequestHandler.get() or Django view functions. 
    """ 

Esecuzione di un piccolo test con i rendimenti nel gestore e decorato con @ ndb.toplevel sembra ancora lavorare, e sembra che si può rimuovere @ ndb.synctasklet dal gestore.

Per quanto riguarda l'inclusione di @ ndb.tasklet sui metodi che chiamano put_async(): Se non stai cedendo su put_async(), non è necessario includere @ ndb.tasklet sul metodo circostante (@ ndb.toplevel si occuperà di ottenere i risultati dal put_async())

+12

Buona risposta! Le regole possono essere riassunte come segue: (1) se una funzione usa "yield" dovrebbe ndb.tasklet, ndb.synctasklet o ndb.toplevel. (2) una funzione racchiusa in ndb.tasklet restituisce un futuro (e puoi renderlo o chiamare esplicitamente get_result()). (3) ndb.synctasklet è come avvolgerlo in ndb.tasklet ma chiamando implicitamente get_result(). (4) ndb.toplevel è come ndb.synctasklet ma attende anche che tutte le operazioni in sospeso siano completate. –