public bool ClaimChunk(JobChunkBase chunk, IdString jobRunnerId, DateTime startDate)
{
var claimChunk = _mongoCollection.Update(
Query.And(
Query<JobChunkBase>.EQ(j => j.Id, chunk.Id),
Query<JobChunkBase>.EQ(j => j.JobRunnerId, IdString.EmptyId)
),
Update<JobChunkBase>
.Set(j => j.JobRunnerId, jobRunnerId.ToString())
.Set(j => j.DateStarted, startDate)
);
// If we managed to update the chunk in the databases then the chunk will have been successfully claimed
return claimChunk.UpdatedExisting;
}
From what I can tell though, this wouldn't necessarily work. If two job runners issue that query at very near the same time, they could both get the job returned by the query and then both issue an update (since the Query and Update are performed separately using an update statement).
The following seems like better code in this situation:
public bool ClaimChunk(JobChunkBase chunk, IdString jobRunnerId, DateTime startDate)
{
var claimChunk = _mongoCollection.FindAndModify(
Query.And(
Query<JobChunkBase>.EQ(j => j.Id, chunk.Id),
Query<JobChunkBase>.EQ(j => j.JobRunnerId, IdString.EmptyId)
),
SortBy<JobChunkBase>.Descending(x => x.Id),
Update<JobChunkBase>
.Set(j => j.JobRunnerId, jobRunnerId.ToString())
.Set(j => j.DateStarted, startDate),
returnNew: true
);
// If we managed to update the chunk in the databases then the chunk will have been successfully claimed
return claimChunk.ModifiedDocument != null;
}
Note that this code makes use of an IdString which is simply a helper class to treat Mongo ObjectIds as strings. EmptyId is just the string equivalent of ObjectId.Empty then.
As such, I guess my initial question could be framed more formally as: "are the two blocks of code above functionally equivalent or am I right to suspect that the only the second piece of code will do what I want - i.e. ensure that only a single job runner claims a any particular chunk?"
Cheers,
James