I am trying to run a test case and trying to pass two schedules inside like below:
var itemToAdd = new ScheduleInputItemDto
{
Start = DateTime.UtcNow,
End = DateTime.UtcNow.AddHours(1),
ProdType = "Prod1"
};
var response = await Task.WhenAll(addItemRequest.Post(itemToAdd, false), addItemRequest.Post(itemToAdd, false));
This will post two items with same start and end time, which is causing a race condition
AddItem calls the DAO layer like below.
public Schedule()
{
ScheduleItems = new List<ScheduleItem>();
}
public ICollection<ScheduleItem> ScheduleItems { get; set; }
public void AddItem(DateTime start, DateTime end, string cementType, DateTime now)
{
var item = new ScheduleItem(start, end, cementType, now);
ScheduleItems.Add(item);
ConcurrentBag<ScheduleItem> concurrentBag = new ConcurrentBag<ScheduleItem>(ScheduleItems.ToList());
item.ValidateDoesNotOverlapWithItems(concurrentBag);
}
But for my case, it is inserting both of them instead of the following check I made:
The validation code is below:
public static void Validate(this ScheduleItem currentItem, ConcurrentBag<ScheduleItem> scheduleItems)
{
if (scheduleItems.Any(scheduleItem => currentItem.Start < scheduleItem.End && scheduleItem.Start < currentItem.End))
{
throw new ValidationException("A conflict happened.");
}
}
The ScheduleItem model has a property named UpdatedOn which can be used as a concurrency token.
After debugging the test case, I saw both of the items posted from inside .WhenAll()
have exact same DateTime
. How can I prevent the later item to be inserted? Optimistic or Pessimistic concurrency control should be used in this case?