Vinod Kumar
Vinod Kumar

Reputation: 489

Using Google App Engine transaction

I have two tasks (a, b) those should be performed in transaction in order avoid inconsistency. I may need to perform one of the tasks or both of them together.

In below code function_a performs task a and function_b performs task b.

@ndb.transactional
def function_a():
    # basic validations
    # read entity of type A
    # make changes to entity
    # write entity
    return

@ndb.transactional
def function_b():
    # basic validations
    # read entity of type B
    # make changes to entity
    # write entity
    return

So if I need to perform task a and b together. I can perform as below :-

def function_ab():
    function_a()
    function_b()
    return

but this implementation will not maintain consistency of A and B together, so I need to make it transactional too.

@ndb.transactional
def function_ab():
    function_a()
    function_b()
    return

So, in implementation like this is using transaction multiple times (once on function_ab and once for individual funcion_a and function_b) for the sake of code reusability. If I do not go for code reusability I can do some like below :-

@ndb.transactional
def function_ab():
    # basic validations
    # read entity of type A
    # make changes to entity
    # write entity

    # basic validations
    # read entity of type B
    # make changes to entity
    # write entity    
    return

I do not know much about how transactions work in app engine, so my question is, Is there any drawback (performance etc.) of using transactions with code reusability over I do not go for code reusability and does the code reusability approach really work?

Upvotes: 1

Views: 143

Answers (1)

Dan Cornilescu
Dan Cornilescu

Reputation: 39834

You can't nest transactions, your transactional function_ab() will give an error.

But you can still arrange the code for re-use by ensuring only the top level(s) functions are transactional while the inner ones just check that they are indeed inside a transaction. Maybe something along these lines:

def function_a():
    assert ndb.in_transaction()
    return

def function_b():
    assert ndb.in_transaction()
    return

@ndb.transactional
def function_ab(do_a, do_b):
    if do_a:
        function_a()
    if do_b:
        function_b()

Your usage pattern is actually textbook fit for using ndb async tasklets, even more efficient. Look for the get_cart_plus_offers() example in Tasklets, Parallel Queries, Parallel Yield.

Upvotes: 1

Related Questions