fix: implement exponential backoff strategy for concurrency exceptions in SaveChangesAsync
This commit is contained in:
@@ -352,18 +352,36 @@ public class JellyfinDbContext(DbContextOptions<JellyfinDbContext> options, ILog
|
||||
}
|
||||
catch (DbUpdateConcurrencyException ex)
|
||||
{
|
||||
// When marking items as played in quick succession, concurrency conflicts can occur.
|
||||
// To resolve this, we'll reload the conflicting entities from the database and retry.
|
||||
logger.LogWarning(ex, "Concurrency exception, retrying operation.");
|
||||
// Concurrency conflicts can occur when marking items as played in quick succession.
|
||||
// To resolve this, we'll retry the operation with an exponential backoff strategy.
|
||||
logger.LogWarning(ex, "Concurrency exception, retrying operation with exponential backoff.");
|
||||
|
||||
foreach (var entry in ex.Entries)
|
||||
var maxRetries = 3;
|
||||
var delay = TimeSpan.FromMilliseconds(100);
|
||||
|
||||
for (var i = 0; i < maxRetries; i++)
|
||||
{
|
||||
// Reload the entity from the database to get the latest version
|
||||
await entry.ReloadAsync(cancellationToken).ConfigureAwait(false);
|
||||
try
|
||||
{
|
||||
foreach (var entry in ex.Entries)
|
||||
{
|
||||
// Reload the entity from the database to get the latest version
|
||||
await entry.ReloadAsync(cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
// Retry saving changes after resolving conflicts
|
||||
return await base.SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
catch (DbUpdateConcurrencyException retryEx) when (i < maxRetries - 1)
|
||||
{
|
||||
logger.LogWarning(retryEx, "Concurrency exception on retry {RetryCount}, delaying for {Delay}ms.", i + 1, delay.TotalMilliseconds);
|
||||
await Task.Delay(delay, cancellationToken).ConfigureAwait(false);
|
||||
delay *= 2; // Exponential backoff
|
||||
}
|
||||
}
|
||||
|
||||
// Retry saving changes after resolving conflicts
|
||||
return await base.SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken).ConfigureAwait(false);
|
||||
// If all retries fail, rethrow the last exception
|
||||
throw;
|
||||
}
|
||||
catch (DbUpdateException ex)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user