fix(infra): repair TransferFiles compensation + tidy MassTransit consistency

Fix (recoverability bug):
- TransferFilesToBucketActivity returned Completed() with no log, so its
  compensation could never delete the transferred files (orphaned objects on
  fault). IStorageService.TransferFilesAsync now returns the real uploaded
  keys; the activity logs them so Compensate can remove them. Also drops the
  Path.Combine key recomputation (produced backslash keys on Windows).

Consistency / DRY:
- Normalize all courier activities to internal + folder-based namespaces
  (several were public and in the flat .Activities namespace)
- Extract the duplicated exponential retry into UseStandardRetry
- Unify endpoint-name logic into a single EndpointHelper (remove the parallel
  MassTransitEndpointNames helper)

Build: 0 warnings, 0 errors.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-05 04:58:27 +02:00
co-authored by Claude Opus 4.8
parent 423e06baf9
commit d08d82a483
15 changed files with 49 additions and 71 deletions
@@ -105,12 +105,13 @@ namespace Musify.Infrastructure.Services
await amazonS3.DeleteObjectAsync(request, cancellationToken);
}
public async Task TransferFilesAsync(string sourceDirectory, string bucket, string route, CancellationToken cancellationToken)
public async Task<IReadOnlyList<string>> TransferFilesAsync(string sourceDirectory, string bucket, string route, CancellationToken cancellationToken)
{
var trasnsferUtility = new TransferUtility(amazonS3);
var files = Directory.GetFiles(sourceDirectory, "*");
var uploadedKeys = new List<string>();
var successCount = 0;
var failedCount = 0;
@@ -144,6 +145,7 @@ namespace Musify.Infrastructure.Services
},
cancellationToken);
upload.State = UploadState.Successful;
uploadedKeys.Add(key);
successCount++;
logger.LogDebug("Transferred file to S3 {Bucket}/{Key}", bucket, key);
}
@@ -158,6 +160,8 @@ namespace Musify.Infrastructure.Services
await database.SaveChangesAsync(cancellationToken);
logger.LogInformation("File transfer completed to {Bucket}/{Route}. Success: {SuccessCount}, Failed: {FailedCount}", bucket, route, successCount, failedCount);
return uploadedKeys;
}
public async Task UploadFileAsync(string filePath, string bucket, string key, CancellationToken cancellationToken)