This will be a bit of a combo question, mostly because I'd like to get some more background info.
The main question:
I'm trying to do a transaction that involves an RPC call to another REST service, that will update some remote data. For example, say the RPC call tells the remote server that I purchased something. In nonfunctional python pseudocode it'll be something like:
def txn_purchase():
a = ModelA.objects.get(blah)
httpresult = HttpPurchaseRPC(url, a.foo)
a.receipt = httpresult.get_receipt() # This raises an error if the request fails
a.save()
db.run_in_transaction(txn_purchase)
I'm pretty sure that transactions only ensure datastore consistency (so in this case, entity a will be consistent), and it doesn't ensure consistency with the RPC. Is it possible to build something on top of this that ensures consistency with the RPC as well?
To me it looks like I'll have a potential problem case if the RPC succeeds, but the datastore transaction failed to save. How do I get around this?
The hazy concept in my mind is to implement a 2-stage purchase:
Is this the "best practice" way to do it, or is there something better?
Background questions on transactions:
Thanks!
You sort of have the right idea here: the way you should do this is to farm out the RPC to a separate deferred task. Tasks that are enqueued within a transaction can have a flag set to ensure they only get enqueued if the transaction succeeds.
There's no magic backend that runs transactions. And they're not retried automatically: again, unless they are part of a task, as tasks are retried until they return successfully.