我有一个带有SQL Server的ASP.NET Core MVC应用程序。在SQL Server中,有一个Job
表。该应用程序的页面显示了Job
表中的信息,还具有一个Next
按钮。当用户单击Next
按钮时,它将保存当前作业,并从Job
表中获取下一个可用的作业。
// This is jQuery Ajax POST on Next button click
[HttpPost]
public asyc Task<ActionResult> Next(JobModel model)
{
// Save Current Job
var jobEntity = _dbContext.Jobs.Where(x=>x.JobID == model.JobID).SingleOrDefaultAsnc();
MapModelToEntity(model, jobEntity);
await _dbContext.SaveChangesAsync();
// Get Next Job
var userID = GetUserIDFromSession();
var job = await _dbContext.Jobs
.Where(x => x.UserID == null)
.OrderBy(x => x.CreatedDateTime)
.FirstOrDefaultAsync();
if(job != null)
{
job.UserID = userID;
// Noticing DbUpdateConcurrencyException here
await _dbContext.SaveChangesAsync();
var jobModel = ConvertJobEntityToJobModel(job);
return Ok(jobModel);
}
return Ok(false);
}
在任何给定时间,将有200多个用户查看该页面并单击下一步按钮。用户将查看作业的内容,然后选择/取消选择一个复选框,然后单击下一步。因此,在单击“下一步”按钮之前,用户最多会花费5到10秒(可能更少)。
此外,我们还有一个后台作业(使用hangfire),该作业每分钟运行一次,并根据特定条件将新行插入Jobs
表中。
鉴于此,当前在向用户分配下一个作业时看到很多DbUpdateConcurrencyException
。以及后台作业中的超时。
我尝试过:
分配下一个作业时,我尝试在有DbUpdateConcurrencyException
时添加重试逻辑。 (这减少了并发异常的数量,但仍不能提供完整的证据)
我还发现了一些解决方案,可以使用事务处理并发并设置隔离级别,如article中所述。 (为此,我可能需要将代码移至存储过程)
但是,我正在考虑实现一个队列。因此,当用户单击下一步时,保存当前作业,然后将用户置于队列中。然后以某种方式在他第一次进入队列时分配工作。
但是考虑到Http的无状态和断开连接的性质,我不确定,首先,如果这是一个好主意,其次,如果是,我将如何做到这一点。可能正在使用jQuery Ajax不断轮询以获取Next Job?
// jQuery ajax POST
[HttpPost]
public async Task<ActionResult> Save(JobModel model)
{
//Save current Job
}
//jQuery ajax start polling this method after Save is done
[HttpGet]
public asyc Task<ActionResult> GetNextJob()
{
// Get Current User From Queue
// If he is first in the Queue then assign next job
}
我想知道是否有使用队列来处理并发问题的设计模式?任何想法将不胜感激