使用队列处理并发问题的设计模式

时间:2019-09-17 17:53:53

标签: c# sql-server asp.net-core concurrency .net-core

我有一个带有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
 }

我想知道是否有使用队列来处理并发问题的设计模式?任何想法将不胜感激

0 个答案:

没有答案