ndb.transaction_async() vs async calls inside a transaction
Asked Answered
S

1

12

I'm in the process of moving my ndb codebase to async as much as possible where it makes sense. There is a scenario where I'm not quite sure how to proceed: transactions.

As I see it, I have 3 options available:

Option 1: Call ndb.transaction() synchronously, and have the transaction's function call async methods.

def option_1():
    @ndb.tasklet
    def txn():
        e = yield Foo.get_by_id_async(some_id)
        if e is None:
            e = yield Foo().put_async()
        raise ndb.Return(e)

    # The doc for ndb.transaction() says that it takes a function or tasklet.
    # If it's a tasklet, does it wait on the Future that is returned?
    # If it doesn't wait, what is the proper way to call a tasklet in a transaction
    # and get access to its return value?
    return ndb.transaction(txn)

Option 2: Call ndb.transaction() asynchronously, and have the transaction's function call sync methods.

@ndb.toplevel
def option_2():
    def txn():
        e = Foo.get_by_id(some_id)
        if e is None:
            e = Foo().put()
        return e

    result = yield ndb.transaction_async(txn)
    return result

Option 3: Call ndb.transaction() asynchronously, and have the transaction's function call async methods.

@ndb.toplevel
def option_3():
    @ndb.tasklet
    def txn():
        e = yield Foo.get_by_id_async(some_id)
        if e is None:
            e = yield Foo().put_async()
        raise ndb.Return(e)

    result = yield ndb.transaction_async(txn)
    return result

I feel like option 3 is the one to go to, but I'd rather rely on an expert opinion/advice...

Skeleton answered 12/2, 2013 at 3:10 Comment(0)
S
9

Yeah, #3 is definitely the way to go. The other two have the problem that they mix async and sync code and that's generally not a good thing to do except at the very top level of your app.

PS. Indeed the transaction waits for the callback if it is a tasklet.

Somnolent answered 12/2, 2013 at 17:18 Comment(1)
I know this is an old answer, but from what I see in the source, all of the transaction/transactional functions in ndb/model.py ultimately end up at the transaction method of the Context class... which is itself marked as a @tasklet. it would seem then that any code inside of a transaction would need to be async, else it would be mixing sync/async code, yes? github.com/GoogleCloudPlatform/datastore-ndb-python/blob/master/…Ishii

© 2022 - 2024 — McMap. All rights reserved.