I'm getting what I think to be a deadlock when trying to run a bunch of linq queries in parallel.
I am running a Task.WhenAll()
on this method:
public async Task<MetabuildScan> GetLatestMetabuildScanAsync(string buildId)
{
var metabuildScanStatuses = new[] { "Completed", "Referenced" };
// Get the latest metabuild scan for this image build
var latestScan = await (from scan in _qsaContext.MetabuildScans
where scan.SoftwareImageBuildId == buildId
&& metabuildScanStatuses.Contains(scan.SIScanStatus)
orderby scan.SIScanStartedOn descending
select scan).FirstOrDefaultAsync();
// If there is a related scan, then use that one, else, use the one we just got
var latestCompletedScanId = latestScan?.RelatedScanId ?? latestScan?.Id;
return await _qsaContext.MetabuildScans
.FirstOrDefaultAsync(scan => scan.Id == latestCompletedScanId);
}
I am getting a System.InvalidOperationException: A second operation started on this context before a previous operation completed. Any instance members are not guaranteed to be thread safe.
_qsaContext
was created using Entity-Framework Core.
At first, I thought the FirstOrDefaultAsync
would fix my issue (I had a non-asynchronous FirstOrDefault
in there at first), but it didn't.
I'm wondering what the best solution to get around this deadlock would be. The table I am selecting from is a large table, so I can't pull the whole table into memory.
Entity Framework DbContext is not thread safe. You can't run parallel queries against it like you are attempting to do.
If you need to have a shared context for your queries that you'll need to await each one individually and sequentially.
If they don't need a shared context but do need to run in parallel then you'll need to have a separate context for each query.
If using a DI framework, perhaps you can look into making your DbContext Transient (instead of what I'm assuming is Scoped) and injecting that into a query class that will call your query methods.