Hi I need some advice on async method run by Task.WhenAll(). It's dotnet core 3 project and context and serviced are added as AddScoped.
When I run DoWorksAysnc method I always get an issue "A second operation started on this context before a previous operation completed. This is usually caused by different threads using the same instance of DbContext. For more information on how to avoid threading issues with DbContext"
I understand that DbContext is not thread safe. but is there anyway I can run the DowksAsync method Concurrently..?
Thanks,
   public async Task DoWorksAsync(List<int> ids)
        {
            
            if (ids.Count > 0)
            {
                var listOfTasks = new List<Task>();
                foreach(var id in ids)
                {
                    var task = Task.Run(async () => await UpdateDataById(id));
                    listOfTasks.Add(task);
                }
                await Task.WhenAll(listOfTasks);
            }
        }
And UpdateDataById method is
 public async Task UpdateDataById (int id)
        {
            try
            {
                //Get products from webservice
                List<Product> products = await _searchService.GetItemsByIdAsync(id);
                await _dataService.CreateTableIfNotExist(id); //Method inside is await _dbContext.Database.ExecuteSqlRawAsync(string.Format(_sqlCreateTableIfNotExist, id));
                // UpdateProductsToDataTable method includes truncate table and bulkcopy.writeToServerAsync(tablename)
                //await _dbContext.Database.ExecuteSqlRawAsync(string.Format("Truncate Table {0}", tableName));    
                //await bulkcopy.WriteToServerAsync();
              
                if (await _dataService.UpdateProductsToDataTable(id,products) == true) 
                {
                   await _emailService.sendEmailNotificationAsync();
                }
                _logService.AddLog("process is done"); 
                _unitOfWork.SaveAsync(); //_context.SaveChangesAsync()
            }
            catch (Exception ex)
            {
                await _logService.AddErrorLog(new ErrorLog
                {
                    Id= id,
                    ErrorMessage = ex.Message
                });
                _unitOfWork.SaveAsync();
            }
        }
                Although you know this, DbContexts are not thread safe, end of story..
The issue is common, and this fix is simple if you follow these rules of thumb
DbContext, they are already cached internally. If you have a repository (and I really suggest your shouldn't), never hold the DbContext as an instance member unless you are absolutely certain it is thread safe and it is being used very discreetly for small workloads. However see point 2.DbContext in a using statement if you can.DbContext from multiple threads (they are not thread safe). See point 1 and 2 respectivelyIf you really need to do this, ensure your DbContext is a separate instance for each thread through one means or another.
Or as suggested by Jeremy Lakeman. Make sure the context is unique for each method call.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With