What is the best way to keep code modular and decoupled but avoid entering a transaction twice?
Entities often have class methods to load, modify, and store data. Often, this must be transactional to be consistent with child/sibling/cousin entities. Here is the pattern:
class MyEntity(db.Model):
# ... some properties
@classmethod
def update_count(cls, my_key):
def txn():
me = db.get(my_key)
me.count += 23
me.put()
OtherEntity.update_descendants(ancestor=me)
return db.run_in_transaction(txn)
Usually, you should fetch entities, modify them, and store them in once block. That technique is more performant; but sometimes performance is less important than modularity and maintainability. The two updates should be decoupled. (Perhaps update_descendants
is called often in isolation, and it's responsible for storing the data.)
But, the following code is a bug:
class OtherEntity(db.Model):
# ... some properties
@classmethod
def update_descendants(cls, ancestor):
def txn(): # XXX Bug!
descendants = cls.all().ancestor(ancestor).fetch(10)
for descendant in descendants:
descendant.update_yourself(ancestor.count)
db.put(descendants)
return db.run_in_transaction(txn)
That raises an exception:
>>> MyEntity.update_count(my_key=some_key_i_have)
Traceback (most recent call last):
...
BadRequestError: Nested transactions are not supported.
So how can I get the best of both worlds: modularity, and correctness?