[英]Hangfire with Entity Framework - DbContext concurrency issues
I have a hangfire service responsible for two jobs: 我有一个空中篝火服务处,负责两项工作:
Pending
emails. Pending
电子邮件。 I am using ASP.NET MVC (5.2.3) , with StructureMap (4.5.1) for creating an IoC container for Dependency Injection, together with Hangfire (1.6.19) 我正在使用ASP.NET MVC(5.2.3)和StructureMap(4.5.1)来创建用于依赖项注入的IoC容器以及Hangfire(1.6.19)
The flow is: 流程为:
Pending
status. Pending
状态推送到数据库中。
DbContext
to retrieve information from the database) DbContext
从数据库中检索信息) Pending
emails and composes an email for each of these using System.Net.Mail
. System.Net.Mail
拾取所有Pending
电子邮件,并为每个电子邮件撰写一封电子邮件。 Both of these jobs work fine, except if there are multiple jobs creating emails at the same time. 这两个工作都可以正常工作,除非有多个工作同时创建电子邮件。
For instance: If there are 10 jobs fired at the same time from the front-end to generate the emails, the job fails with the error: 例如:如果前端同时触发了10个作业以生成电子邮件,则该作业将失败并显示以下错误:
A second operation started on this context before a previous asynchronous operation completed.
在先前的异步操作完成之前,第二操作在此上下文上开始。 Use 'await' to ensure that any asynchronous operations have completed before calling another method on this context.
使用“ await”来确保在此上下文上调用另一个方法之前,所有异步操作都已完成。 Any instance members are not guaranteed to be thread safe.
不保证任何实例成员都是线程安全的。
The line that is throwing this error is using await
, but I am thinking that it is because there are different threads accessing the context at the same time: 引发此错误的行正在使用
await
,但我认为这是因为有不同的线程同时访问上下文:
var ids = await context.Objects
.Where(x => x.id == clientId && !x.IsDeleted)
.Select(x => x.id)
.ToListAsync();
I have set up the DbContext trying different scopes, Transient
and AlwaysUnique
, but the error persists. 我设置了DbContext尝试使用不同的范围
Transient
和AlwaysUnique
,但是错误仍然存在。
Also, this doesn't always happen at the same line, basically anywhere where the context is being used in the involved repositories - if both jobs hit the same line at the same time. 而且,这并不总是在同一行上发生,基本上不会发生在所涉及的存储库中使用上下文的任何地方-如果两个作业同时在同一行上发生。
The jobs retry, and the emails are being sent out pretty much one per minute, which might not work if there are hundreds of emails to be processed and sent out (which is the problem, in my scenario) 重试作业,每分钟发送一封电子邮件,如果有数百封电子邮件要处理和发送出去,则这可能不起作用(在我的方案中,这是问题所在)
The issue was resolved when I used the ContainerScoped
LifeCycle. 当我使用
ContainerScoped
LifeCycle时,此问题已解决。
ContainerScoped in this case means that a registration will be built once per Container, such that the root container, any child or profile container, and every single nested container will build its own object instance
在这种情况下,ContainerScoped意味着将为每个Container构建一次注册,这样根容器,任何子容器或配置文件容器以及每个嵌套容器都将构建自己的对象实例
This means that there is a new instance of the DataContext
for every job fired from hangfire (If I understand it correctly, I might speak under correction) 这意味着从hangfire触发的每个作业都有一个
DataContext
的新实例(如果我正确理解的话,我可能会更正地说)
Specifically for the Datacontext, I had to enable MARS (Multiple Active Result Sets)
which enables SQL Server to allow the execution of multiple batches on a single connection. 特别是对于Datacontext,我必须启用MARS
(Multiple Active Result Sets)
,这使SQL Server允许在单个连接上执行多个批处理。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.