Running same task multiple times in parallel with EF Core

asp.net-core-2.2 c# entity-framework-core

Question

I have a Task that generates a PDF file for an order (it takes about 10 seconds to create one PDF):

public async Task GeneratePDF(Guid Id) {
   var order = await 
      _context
      .Orders
      .Include(order => order.Customer)
      ... //a lot more Include and ThenInclude statements
      .FirstOrDefaultAsync(order ==> order.Id == Id);
   var document = ...  //PDF generated here, takes about 10 seconds
   order.PDF = document ;
   _context.SaveChangesAsync();
}

I tried the following:

public async Task GenerateAllPDFs() {
   var orderIds = await _context.Orders.Select(order=> order.Id).ToListAsync();
   foreach (var id in orderIds)
   {
      _ = GeneratePDF(id).ContinueWith(t => Console.WriteLine(t.Exception), TaskContinuationOptions.OnlyOnFaulted);
   }
}

this gives me the error:

System.ObjectDisposedException: Cannot access a disposed object. A common cause of this error is disposing a context that was resolved from dependency injection and then later trying to use the same context instance elsewhere in your application. This may occur if you are calling Dispose() on the context, or wrapping the context in a using statement. If you are using dependency injection, you should let the dependency injection container take care of disposing context instances.

If I change the task as follows...

public async Task GenerateAllPDFs() {
   var orderIds = await _context.Orders.Select(order=> order.Id).ToListAsync();
   foreach (var id in orderIds)
   {
      _ = await GeneratePDF(id);
   }
}

...it runs the task for each order in series, taking ages to complete (I have a few thousands orders, taking about 10 seconds per order)...

How can I run this task in parallel for all orders in the context, so that the time it takes to complete is much less than sequential processing?

1
0
10/30/2019 6:36:21 PM

Popular Answer

You can map your order IDs to tasks and await them all like:

public async Task GeneratePDF(Order order) {
   var document = ...  //PDF generated here, takes about 10 seconds
   order.PDF = document ;
}

public async Task GenerateAllPDFs() {
   var orderIds = await _context.Orders.ToListAsync();
   var tasks = orderIds.Select((order) => GeneratePDF(order).ContinueWith(t => Console.WriteLine(t.Exception), TaskContinuationOptions.OnlyOnFaulted));
   await Task.WhenAll(tasks);
   await _context.SaveChangesAsync();
}
2
10/30/2019 6:20:31 PM


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow