Я взял кодовую базу у кого-то другого. Это веб-приложение, построенное на Angular 8 (клиент) и .NET Core 3.0 (сервер).
Краткое описание приложения:
- Частые уведомления хранятся в базе данных,с прикрепленным к нему SqlTableDependency для обнаружения новых уведомлений.
- Когда появляются новые уведомления, сервер предлагает всем клиентам запрашивать обновленный список на основе их пользовательских фильтров. Эти клиент-серверные запросы происходят через HttpPost с фильтром в качестве параметра.
Проблема возникает, когда за один раз приходит слишком много уведомлений. Например, когда поступают 10 новых уведомлений, сервер одновременно отправляет 10 запросов на обновление клиенту, в результате чего клиент немедленно отправляет 10 запросов HttpPost в API.
API получает фильтр из POST,использует его для запроса к базе данных и возвращает отфильтрованный результат вызывающему клиенту. Однако, когда 10 из них прибывают одновременно, это вызывает ошибку DbContext - более конкретно:
Вторая операция, запущенная в этом контексте перед завершением предыдущей операции. Обычно это вызвано тем, что разные потоки используют один и тот же экземпляр DbContext.
public class AlarmController : Controller
{
private readonly IAlarmRepository alarmRepo;
private readonly ISiteRepository siteRepo;
public AlarmController(IAlarmRepository alarmRepo, ISiteRepository siteRepo)
{
this.alarmRepo = alarmRepo;
this.siteRepo = siteRepo;
}
[HttpPost("filter")]
public async Task<IActionResult> FilterAlarm([FromBody] AlarmRequest alarmRequest)
{
var snmpReciverList = await this.alarmRepo.GetFilteredSNMPReceiverHistory(alarmRequest.FromDate, alarmRequest.ToDate);
var siteList = await this.siteRepo.GetSiteListFiltered(int.Parse(alarmRequest.Filter), alarmRequest.SiteName);
return Ok(await SNMPHistoryMapping.DoMapping(siteList, snmpReciverList);
}
Этот HttpPost возвращает Ok()
со списком запрошенных данных, в котором выполняется некоторое сопоставление:
IEnumerable<Site> sites = siteList;
IEnumerable<SnmpreceiverHistory> histories = snmpReceiverList;
IEnumerable<SNMPHistoryResponse> data = (from s in sites
join rh in histories on s.Address equals rh.Ipaddress
where priority > 0 ? s.SitePriority == priority : true
&& !string.IsNullOrEmpty(trap) ? rh.AlarmDescription.Contains(trap) : true
select new SNMPHistoryResponse()
{
AlarmDescription = rh.AlarmDescription,
EventType = rh.EventType,
OnOffStatus = rh.OnOffStatus,
ParentSiteName = TraceFullParentDescription(s.Parent),
ReceiveTime = rh.ReceiveTime,
RepeatCount = rh.RepeatCount,
SiteName = s.Description,
SitePriority = s.SitePriority,
Status = AlarmStatus.GetStatusDescription(rh.EventType),
Value = rh.Value
});
Когда несколько этих [HttpPost("filter")]
запросов поступают одновременно, создается впечатление, что для каждого из них создается новый поток. Все они подключаются к одному и тому же DbContext, и следующий запрос начинается до того, как завершится предыдущий.
Я могу решить эту проблему, помещая задержки между каждым запросом от клиента, но я хочу более надежное решение на стороне сервера, чтобыэто, эффективно обрабатывая эти конкретные запросы последовательно.
Обратите внимание, что это EF Core и .NET Core 3.0, которые не имеют SynchronizationContext.