Multiple operations (all or nothing approach)

When my handler receives a request which contains some data and one or more images I want to achieve the following:

  1. save data into db
  2. upload images to cloud storage
    If either of the actions fails I want to roll back everything, all or nothing approach.

I’m thinking to do this inside database transaction

 ...
using (var transaction = _dbContext.Database.BeginTransaction())
{
   try{
        // 1. save data 
        // 2. upload files to cloud storage
   }
   catch{  await transaction.RollbackAsync(); }
}

or to

var tasks = new List<Task>();
tasks.Add(Task.Run(() =>
{
   // save data 
}));
tasks.Add(Task.Run(() =>
{
   // upload files to cloud storage
}));
Task t = Task.WhenAll(tasks);
t.Wait();

What would you suggest, is there a better way?

>Solution :

I highly doubt that your cloud storage supports transactions, so if you need some kind of guarantees then you will not end up with uncleaned data then you should look into something similar to standard microservices approach – eventual consistency for example with Saga pattern. In short idea is that handler saves the data in temporary storage (table), uploads files (maybe to temporary location also and maintaining the list so compensating actions can be performed) and if everything goes smoothly – commits data from temporary storage to database, if something fails during the pipeline – perform the compensating actions (clean up the uploads, clean up the temporary storage). In theory handler can fail in the middle of the process without reporting the failure – so potentially you can perform some kind of background clean up (i.e. clean up all "sagas"/temp data/uploads older then some time period or last updated older then some period).

Implementation details heavily depend on the actual infrastructure, requirements and constraints. Also note that if failures are rarely expected and you can tolerate some amount of "trash" – then personally I would go with the first approach.

Leave a Reply