For speed we sometimes return response to consumer before state is saved in DB. Sometimes (Mostly for our automated consumers) this can break because the want to make actions on the saved data before it is saved. I wrote this little helper
public async Task<TEntity> GetWithRetry<TEntity>(Expression<Func<TEntity, bool>> predicate, string errorOnTimeout) where TEntity : class
{
var stopwatch = new Stopwatch();
stopwatch.Start();
do
{
var entity = await _context.DbSet<TEntity>().FirstOrDefaultAsync(predicate);
if(entity == null)
await Task.Delay(100);
else
return entity;
} while(stopwatch.Elapsed < TimeSpan.FromSeconds(1000));
throw new Exception(errorOnTimeout);
}
Used like
var existingBooking = await GetWithRetry<Booking>(b => b.BookingKey == confirmCommand.BookingKey, "Booking key not found");
Any pitfalls? Task.Delay
should scale well since it returns the thread to the pool, and if the data exists in DB the first time around it should not give much more overhead than an extra wrapped task?