I have a very simple .NET core API that serves clients tasks. When a client requests a task, API updates it's status and returns the task to client. However i have noticed that if multiple clients request a task at the same time, they end up getting the same task. Here's relevant controller code:
[HttpPost("next",Name = "RequestJob")]
public ActionResult<QueJobReadDto> RequestJob(Robot robot)
{
var job = _repository.RequestJob();
var registeredJob = _repository.RegisterJob(robot.RobotName, job);
_repository.SaveChanges();
return Ok(_mapper.Map<QueJobReadDto>(registeredJob));
}
As you can see there are two methods used, "RequestJob" and "RegisterJob". RequestJob finds a record with a status of "In Que" and RegisterJob updates the status of the record to "In Progress". Here are the relevant implementations:
public QueJob RequestJob()
{
return _context.QueJobs
.Where(queJob => queJob.Status == "In Que")
.OrderBy(queJob => queJob.JobGuid)
.ToList()
.FirstOrDefault();
}
public QueJob RegisterJob(string worker, QueJob qj)
{
qj.Status = "In Progress";
qj.Start = DateTime.UtcNow;
qj.Worker = worker;
qj.JobGuid = qj.JobGuid;
_context.Update(qj);
return _context.QueJobs.Find(qj.JobGuid);
}
My question is: how can i couple these methods so the clients will never get the same task?
If you want to try out the economy version, add this to the top of your controller
private const int LockTimeoutInMilliseconds = 100;
private static readonly object LockObject = new object();
Then
[HttpPost("next",Name = "RequestJob")]
public ActionResult<QueJobReadDto> RequestJob(Robot robot)
{
if (!Monitor.TryEnter(LockObject, LockTimeoutInMilliseconds))
{
// return an approriate error messsage
}
try
{
var job = _repository.RequestJob();
var registeredJob = _repository.RegisterJob(robot.RobotName, job);
_repository.SaveChanges();
return Ok(_mapper.Map<QueJobReadDto>(registeredJob));
}
finally
{
Monitor.Exit(LockObject); // ensure that the lock is released.
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With