Я попытался реализовать оптимистичный параллелизм «работника».
Цель состоит в том, чтобы прочитать пакет данных из одной и той же таблицы базы данных (одна таблица без отношений) с несколькими параллельными «рабочими». Это, похоже, работало до сих пор. Я получаю оптимистичные исключения параллелизма здесь и там, ловлю их и повторяю попытку.
Пока все хорошо, и функция получения данных стабильно работает на моей локальной установке. Однако при перемещении приложения в тестовую среду я получаю странное исключение тайм-аута, которое, даже если оно будет поймано, завершит асинхронную функцию (разорвет цикл while). Кто-то видит недостаток в реализации? Что может вызвать тайм-аут? Что может привести к завершению асинхронной функции?
public async IAsyncEnumerable<List<WorkItem>> LoadBatchedWorkload([EnumeratorCancellation] CancellationToken token, int batchSize, int runID)
{
DataContext context = null;
try
{
context = GetNewContext(); // create a new dbContext
List<WorkItem> workItems;
bool loadSuccessInner;
while (true)
{
if (token.IsCancellationRequested) break;
loadSuccessInner = false;
context.Dispose();
context = GetNewContext(); // create a new dbContext
RunState currentRunState = context.Runs.Where(a => a.Id == runID).First().Status;
try
{
// Error happens on the following line: Microsoft.Data.SqlClient.SqlException: Timeout
workItems = context.WorkItems.Where(a => a.State == ProcessState.ToProcess).Take(batchSize).ToList();
loadSuccessInner = true;
}
catch (Exception ex)
{
workItems = new List<WorkItem>();
}
if (workItems.Count == 0 && loadSuccessInner)
{
break;
}
//... update to a different RunState
//... if set successful yield the result
//... else cleanup and retry
}
}
finally
{
if (context != null) context.Dispose();
}
}
Я проверил, что EntityFramework (здесь с адаптером MS SQL Server) выполняет полный запрос на стороне сервера, который преобразуется в простой запрос, подобный этому:
SELECT TOP 10 field_1, field_2 FROM WorkItems WHERE field_2 = 0
Запрос обычно занимает ‹1 мс, а время ожидания по умолчанию составляет 30 с.
Я убедился, что запросов на отмену не было.
Это также происходит, когда есть только один рабочий процесс, и никто другой не обращается к базе данных. Я знаю, что тайм-аут может произойти, когда ресурс занят или заблокирован. Но до сих пор я никогда не видел тайм-аут ни в одном другом запросе.