Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Correct usage of Async/Await for Multiple Tasks To Db

I have a simple scenario but I would like to know if my approach is correct, is it better advised to chose a single task to save my failed orders or can i kick off and fire off multiple tasks and wait for them all to complete. What is the correct approach for this scenario when it comes to connecting to a Db and saving entities.

I already have a single task based version of the below that saves one entity into the db.

    public async static Task SaveOrdersAsync(OrderService oService, OrderItemService oiService, IEnumerable<OrderTemplate> toSaveList, IUnitOfWork uow, IProgress<string> progress)
    {
        var toSave = toSaveList as IList<OrderTemplate> ?? toSaveList.ToList();
        var tasks = new Task[toSave.Count()];

        for (var i = 0; i < tasks.Length; i++)
        {
            var i1 = i;

            tasks[i] = new Task(() => SaveToDb(oService, oiService, toSave.ElementAt(i1), uow), TaskCreationOptions.PreferFairness);

            var message = string.Format("- Order: {0} has been resaved.\n", toSave.ElementAt(i1).Order.FriendlyId);

            if (progress != null)
                progress.Report(message);
        }

        await Task.WhenAll(tasks);
    }

At the moment, I have tested the above and believe that tasks have not started as the progress bar keeps looping around. My assumption is that Task.WhenAll should start my tasks for me - thats what I think?

or should be using this in the loop:

      tasks[i] = Task.Run(() => SaveToDb(oService, oiService, toSave.ElementAt(i1), uow));

I think I am close, just want someone to tell me if I a doing this correctly or not.

Feedback incorporated version:

    public async static Task SaveOrdersAsync(OrderService oService, OrderItemService oiService, IEnumerable<OrderTemplate> toSaveList, IUnitOfWork uow, IProgress<string> progress)
    {   
        var saveList = toSaveList as IList<OrderTemplate> ?? toSaveList.ToList();
        var saveTask = Task.Run(() =>
        {
            foreach (var ot in saveList)
            {
                SaveToDbBatch(oService, oiService, ot);

                var message = string.Format("- Order: {0} has been resaved.\n", ot.Order.FriendlyId);
                if (progress != null)
                    progress.Report(message);
            }
        });

        await saveTask;
        await Cache.UoW.SaveAsync();
    }
like image 575
IbrarMumtaz Avatar asked Dec 09 '25 04:12

IbrarMumtaz


1 Answers

What is the correct approach for this scenario when it comes to connecting to a Db and saving entities.

Generally speaking, you should:

  1. Batch your saves, if possible. In other words, call a single method to update multiple records simultaneously. E.g., EF has SaveChangesAsync.
  2. Use the natural async APIs for your database instead of Task.Run (or - even worse - the task constructor). E.g., EF has SaveChangesAsync.
like image 100
Stephen Cleary Avatar answered Dec 10 '25 18:12

Stephen Cleary



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!