0

I am trying to maintain some cross transactional-ity between different services.

Basically I have a ndb model which would be processed. There is a chance that the transaction might fail after we have saved an object. How would I rollback in such a scenario?

Example

class PersonTable(ndb.Model):
    personId = ndb.StringProperty()
    personName = ndb.StringProperty()
    personAddress = ndb.StringProperty()
    personOldReference = ndb.StringProperty()
    scopeReference = ndb.StringProperty()

    def save():
          self.put()

def some_method(person_id, person_name):
     person = PersonTable.get(person_id)
     person.personName = person_name

     sql_db.saveRelated(person_id, personName)
     person.save()

@ndb.transactional
def outer_method(person_id, person_name):
    person_name = prefix+person_name
    some_method(person_id, person_name)
    post_update_tasks(person_id)

Now I was thinking of something like

def some_method(person_id, person_name):
     person = PersonTable.get(person_id)
     person.personName = person_name

     try:
         sql_db.saveRelated(person_id, personName)
         person.save()
     except Exception as e:
         sql_db.rollback(person_id)
         raise e

This would solve the problem if save fails. But if something fails in the outer_method after, then the transactional fails and ndb will roll back but sql_db would not be able to rollback.

@ndb.transactional
def outer_method(person_id, person_name):
    person_name = prefix+person_name
    some_method(person_id, person_name) ---> This is sucessfull & data is saved in both ndb & sql.
    post_update_tasks(person_id) --> If this fails then ndb is rolled back but not SQL.

How would I solve for this problem? Is there a hook on the model similar to _pre_put_hook which would execute if theres a rollback on ndb?

Shaurya Chaudhuri
  • 3,772
  • 6
  • 28
  • 58

1 Answers1

1

Is there a reason you just couldnt put the try-except-rollback around outer_method?

@ndb.transactional
def _outer_method(person_id, person_name):  # renamed outer_method to _outer_method
    person_name = prefix+person_name
    some_method(person_id, person_name)
    post_update_tasks(person_id)

def outer_method(person_id, person_name):
    try:
        _outer_method(person_id, person_name)
    except:
        sql_db.rollback(person_id)

Also, what does post_update_tasks do? does that launch tasks with appengine taskqueue? you're going to have to migrate to google-cloud-tasks at some point and that doesnt support transactions anymore.

Is there a hook on the model similar to _pre_put_hook which would execute if theres a rollback on ndb?

I believe these are all the 'hooks' you have at your disposal:

https://github.com/googleapis/python-ndb/blob/921ec695e246e548f207b0c6aded7296e4b3b263/google/cloud/ndb/model.py#L6126

Alex
  • 5,141
  • 12
  • 26
  • I cannot put around outer method. In the code we have a Business Object where these things are happening. Over the codebase there are several places we have used that. Now it's not possible to put the try catch everywhere over a large codebase. And it's not reasonable to expect everyone in the large team to start using that pattern going forward. – Shaurya Chaudhuri Jan 19 '22 at 05:16