У меня есть служба Hangfire, отвечающая за две работы:
- Создание объектов электронной почты с соответствующими вложениями (длительный процесс)
- Обработка и отправка
Pendingписем.
Я использую ASP.NET MVC (5.2.3) с StructureMap (4.5.1) для создания контейнера IoC для внедрения зависимостей вместе с Hangfire ( 1.6.19)
Поток:
- The email will be triggered to be created from the front-end, where a Fire and Forget hangfire job is created, pushing it into the database with a
Pendingstatus.- This process uses a few repository objects to create a report of the client in a PDF format (These repositories uses the
DbContextto retrieve information from the database)
- This process uses a few repository objects to create a report of the client in a PDF format (These repositories uses the
- Еще одно повторяющееся задание, собирает все
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, но ошибка не исчезла.
Кроме того, это не всегда происходит в одной и той же строке, практически везде, где контекст используется в задействованных репозиториях - если оба задания одновременно попадают в одну и ту же строку.
Задания повторяются, и электронные письма отправляются примерно раз в минуту, что может не сработать, если есть сотни писем, которые нужно обработать и отправить (что является проблемой в моем сценарии).
Transient, так и наAlwaysUnique, и у меня возникла та же проблема с обоими. Когда я удаляюawaitи меняю.ToListAsync()наToList(), похоже, он работает, как ожидалось ... Я не уверен, как это повлияет на этот вызов другими обычными вызовами api - person Johan Aspeling   schedule 11.03.2019