fix(jobs): retry directories whose reconciliation batch was dropped

This commit is contained in:
2026-08-20 15:54:54 +02:00
parent b2786b487f
commit 22b6e0e702
+20 -12
View File
@@ -121,19 +121,23 @@ public sealed class FileSystemCrawlJob : Job {
if (changed) {
dirsProcessed++;
await ReconcileDirectory(assetDb, currentPath, files!, uploaderId, token,
bool reconciled = await ReconcileDirectory(assetDb, currentPath, files!, uploaderId, token,
(added, updated, deleted) => { filesAdded += added; filesUpdated += updated; filesDeleted += deleted; });
if (existingStates.TryGetValue(currentPath, out var existingState)) {
existingState.LastMtime = currentDir.LastWriteTimeUtc;
} else {
existingStates[currentPath] = new DirectoryScanState {
Id = Guid.NewGuid(),
FolderId = folderId,
Path = currentPath,
LastMtime = currentDir.LastWriteTimeUtc
};
db.DirectoryScanStates.Add(existingStates[currentPath]);
// Only record scan state when the reconciliation batch actually committed; a dropped
// batch leaves the mtime stale so the directory is retried on the next run.
if (reconciled) {
if (existingStates.TryGetValue(currentPath, out var existingState)) {
existingState.LastMtime = currentDir.LastWriteTimeUtc;
} else {
existingStates[currentPath] = new DirectoryScanState {
Id = Guid.NewGuid(),
FolderId = folderId,
Path = currentPath,
LastMtime = currentDir.LastWriteTimeUtc
};
db.DirectoryScanStates.Add(existingStates[currentPath]);
}
}
} else {
dirsSkipped++;
@@ -186,7 +190,8 @@ public sealed class FileSystemCrawlJob : Job {
/// <param name="uploaderId">The system uploader id to backfill, if any.</param>
/// <param name="token">Cancellation token.</param>
/// <param name="report">Callback receiving (added, updated, deleted) counts.</param>
async Task ReconcileDirectory(LactoseDbContext assetDb, string dirPath, FileInfo[] files, Guid? uploaderId,
/// <returns>True when the batch committed; false when it was dropped due to a duplicate-key race.</returns>
async Task<bool> ReconcileDirectory(LactoseDbContext assetDb, string dirPath, FileInfo[] files, Guid? uploaderId,
CancellationToken token, Action<int, int, int> report) {
var prefix = dirPath.TrimEnd(Path.DirectorySeparatorChar) + Path.DirectorySeparatorChar;
var lo = prefix;
@@ -260,12 +265,15 @@ public sealed class FileSystemCrawlJob : Job {
// same new path concurrently). The batch is dropped; the file is found next run.
logger.LogDebug(ex, "Dropped {Count} asset change(s) in {Path} due to a duplicate asset path.",
added + updated + deleted, dirPath);
report(0, 0, 0);
return false;
} finally {
assetDb.ChangeTracker.Clear();
}
}
report(added, updated, deleted);
return true;
}
static bool IsDuplicateKey(DbUpdateException ex) =>