У меня есть служба Hangfire, отвечающая за две работы:
- Создание объектов электронной почты с соответствующими вложениями (трудоемкий процесс)
- Обработка и отправка
Pending
электронных писем.
Я использую ASP.NET MVC (5.2.3) , с StructureMap (4.5.1) для создания контейнера IoC для внедрения зависимости,вместе с Hangfire (1.6.19)
Поток:
- Электронное письмо будет инициировано для создания из внешнего интерфейса, где Fireи задание Forget hangfire создано, помещено в базу данных со статусом
Pending
. - Этот процесс использует несколько объектов репозитория для создания отчета клиента в формате PDF (эти репозитории используют
DbContext
для извлечения информации из базы данных)
- Другое повторяющееся задание, собирает все
Pending
электронные письма и составляет электронное письмо для каждого из них, используя System.Net.Mail
.
Обе эти работы работают нормально, за исключением случаев, когда существует несколько заданий, создающих электронную почтув то же время.
Например: Если из внешнего интерфейса одновременно сгенерировано 10 заданий для создания электронных писем, задание завершается с ошибкой:
Вторая операция началась в этом контексте до завершения предыдущей асинхронной операции.Используйте 'await', чтобы убедиться, что все асинхронные операции завершены, прежде чем вызывать другой метод в этом контексте.Ни один из членов экземпляра не гарантированно является потокобезопасным.
Строка, которая выдает эту ошибку, использует await
, но я думаю, что это потому, что есть разные потоки, обращающиеся к контексту вв то же время:
var ids = await context.Objects
.Where(x => x.id == clientId && !x.IsDeleted)
.Select(x => x.id)
.ToListAsync();
Я настроил DbContext, пробуя разные области, Transient
и AlwaysUnique
, но ошибка не исчезла.
Кроме того, это не всегда происходит в одной и той же строке, в основном везде, где используется контекст в задействованных репозиториях - если оба задания одновременно попадают в одну и ту же строку.
Задания повторяются, и электронные письма отправляются почти по одной в минуту, что может не сработать, если сотни сообщений будут обработаны и отправлены (что является проблемой в моем сценарии)