Say you have this task in an application that consists of two parts:
1) Delivery of a file to an external system (not in your control)
2) A database transaction in our system, with information about said delivery (what was sent, when and by whom)
If any of these two parts fail, our system's state will be inconsistent. If a file has been sent and the db has no information about it, it's an error. Likewise, if the file transfer failed, but the information in the database suggests otherwise, that is also an error.
How would you approach this task to ensure that the database is left in a consistent state after each time the task is attempted?
I'm inexperienced in dealing with problems like this in a proper manner - I could always use the naïve approach and pretend writing to the database will never fail. :-) I wish to do better than that, though.
The two basic variations I see here both leave something to be desired (pseudocode):
try: commitTransaction() deliverFile() catch TransactionError: // No problem, delivery was never attempted. catch DeliveryError: // The system will now say that it was delivered, // even though it wasn't.
try: deliverFile() commitTransaction() catch TransactionError: // The system will now say nothing was delivered, // even though it was. catch DeliveryError: // Easy enough to handle: rollbackTransaction()
I'm sure there is an acceptable solution to this, and that I just can't spot it?