add more resiliency for concurrency exceptions

This commit is contained in:
rootdarkarchon
2025-04-27 13:02:34 +02:00
parent 72020d9227
commit 0e560432ed

View File

@@ -5,6 +5,7 @@ using MareSynchronosShared.Services;
using MareSynchronosShared.Utils.Configuration; using MareSynchronosShared.Utils.Configuration;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Data;
using System.Diagnostics; using System.Diagnostics;
namespace MareSynchronosServer.Services; namespace MareSynchronosServer.Services;
@@ -29,6 +30,7 @@ public class ClientPairPermissionsCleanupService(ILogger<ClientPairPermissionsCl
ConcurrentDictionary<int, List<UserPermissionSet>> toRemovePermsParallel = []; ConcurrentDictionary<int, List<UserPermissionSet>> toRemovePermsParallel = [];
int parallelProcessed = 0; int parallelProcessed = 0;
int userNo = 0; int userNo = 0;
int lastUserNo = 0;
using var db = await _dbContextFactory.CreateDbContextAsync(ct).ConfigureAwait(false); using var db = await _dbContextFactory.CreateDbContextAsync(ct).ConfigureAwait(false);
_logger.LogInformation("Building All Pairs"); _logger.LogInformation("Building All Pairs");
@@ -57,7 +59,7 @@ public class ClientPairPermissionsCleanupService(ILogger<ClientPairPermissionsCl
using var db2 = await _dbContextFactory.CreateDbContextAsync(token).ConfigureAwait(false); using var db2 = await _dbContextFactory.CreateDbContextAsync(token).ConfigureAwait(false);
var user = users[i]; var user = users[i];
if (!allPairs.Remove(user, out var personalPairs)) if (!allPairs.TryGetValue(user, out var personalPairs))
personalPairs = []; personalPairs = [];
toRemovePermsParallel[i] = await UserPermissionCleanup(i, users.Count, user, db2, personalPairs).ConfigureAwait(false); toRemovePermsParallel[i] = await UserPermissionCleanup(i, users.Count, user, db2, personalPairs).ConfigureAwait(false);
@@ -83,15 +85,30 @@ public class ClientPairPermissionsCleanupService(ILogger<ClientPairPermissionsCl
removedEntries += parallelProcessed; removedEntries += parallelProcessed;
_logger.LogInformation("Removing {newDeleted} entities and writing to database", removedEntries - priorRemovedEntries); try
db.Permissions.RemoveRange(toRemovePermsParallel.Values.SelectMany(v => v).ToList()); {
await db.SaveChangesAsync(ct).ConfigureAwait(false); parallelProcessed = 0;
_logger.LogInformation("Removed {newDeleted} entities, settling...", removedEntries - priorRemovedEntries); _logger.LogInformation("Removing {newDeleted} entities and writing to database", removedEntries - priorRemovedEntries);
priorRemovedEntries = removedEntries; db.Permissions.RemoveRange(toRemovePermsParallel.Values.SelectMany(v => v).ToList());
await db.SaveChangesAsync(ct).ConfigureAwait(false);
_logger.LogInformation("Removed {newDeleted} entities, settling...", removedEntries - priorRemovedEntries);
priorRemovedEntries = removedEntries;
lastUserNo = userNo;
}
catch (DBConcurrencyException ex)
{
_logger.LogWarning(ex, "Concurrency Exception during User Permissions Cleanup, restarting at {last}", lastUserNo);
userNo = lastUserNo;
removedEntries = priorRemovedEntries;
continue;
}
finally
{
toRemovePermsParallel.Clear();
}
parallelProcessed = 0;
toRemovePermsParallel.Clear();
await Task.Delay(TimeSpan.FromSeconds(5), ct).ConfigureAwait(false); await Task.Delay(TimeSpan.FromSeconds(5), ct).ConfigureAwait(false);
} }
@@ -142,6 +159,11 @@ public class ClientPairPermissionsCleanupService(ILogger<ClientPairPermissionsCl
_logger.LogInformation("Starting Permissions Cleanup"); _logger.LogInformation("Starting Permissions Cleanup");
await AllUsersPermissionsCleanup(ct).ConfigureAwait(false); await AllUsersPermissionsCleanup(ct).ConfigureAwait(false);
} }
catch (DbUpdateConcurrencyException ex)
{
_logger.LogWarning(ex, "Concurrency Exception during User Permissions Cleanup");
continue;
}
catch (Exception ex) catch (Exception ex)
{ {
_logger.LogError(ex, "Unhandled Exception during User Permissions Cleanup"); _logger.LogError(ex, "Unhandled Exception during User Permissions Cleanup");