Development #9

Merged
wjones merged 7 commits from development into main 2026-07-08 12:15:52 -04:00
Showing only changes of commit 421a8cc092 - Show all commits
@@ -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)
{