Add editorconfig and analyzers, format backend code

This commit is contained in:
2026-09-24 04:54:17 +02:00
parent 87c3f97529
commit c8fe28b07b
367 changed files with 12179 additions and 12459 deletions
@@ -4,35 +4,34 @@ using Microsoft.Extensions.Logging;
using Musify.Application.Contracts;
using Musify.Application.Mixes;
namespace Musify.Infrastructure.Jobs
namespace Musify.Infrastructure.Jobs;
public class DailyMixGenerationJob(
IDatabase database,
IMediator mediator,
ILogger<DailyMixGenerationJob> logger)
{
public class DailyMixGenerationJob(
IDatabase database,
IMediator mediator,
ILogger<DailyMixGenerationJob> logger)
public async Task RunAsync(CancellationToken cancellationToken)
{
public async Task RunAsync(CancellationToken cancellationToken)
var userIds = await database.ListeningHistories
.AsNoTracking()
.Where(history => history.IsCounted)
.Select(history => history.UserId)
.Distinct()
.ToListAsync(cancellationToken);
logger.LogInformation("Starting daily mix generation for {Count} users", userIds.Count);
foreach (var userId in userIds)
{
var userIds = await database.ListeningHistories
.AsNoTracking()
.Where(history => history.IsCounted)
.Select(history => history.UserId)
.Distinct()
.ToListAsync(cancellationToken);
logger.LogInformation("Starting daily mix generation for {Count} users", userIds.Count);
foreach (var userId in userIds)
var result = await mediator.Send(new GenerateMixesForUserCommand(userId), cancellationToken);
if (result.IsError)
{
var result = await mediator.Send(new GenerateMixesForUserCommand(userId), cancellationToken);
if (result.IsError)
{
logger.LogWarning("Failed to generate mixes for user {UserId}: {Error}",
userId, result.FirstError.Description);
}
logger.LogWarning("Failed to generate mixes for user {UserId}: {Error}",
userId, result.FirstError.Description);
}
logger.LogInformation("Finished daily mix generation");
}
logger.LogInformation("Finished daily mix generation");
}
}
@@ -1,13 +1,12 @@
using Mediator;
using Musify.Application.Tracks;
namespace Musify.Infrastructure.Jobs
namespace Musify.Infrastructure.Jobs;
public class ListeningHistoryCleanupJob(IMediator mediator)
{
public class ListeningHistoryCleanupJob(IMediator mediator)
public async Task RunAsync(CancellationToken cancellationToken)
{
public async Task RunAsync(CancellationToken cancellationToken)
{
await mediator.Send(new DeleteStaleUncountedListensCommand(), cancellationToken);
}
await mediator.Send(new DeleteStaleUncountedListensCommand(), cancellationToken);
}
}
@@ -4,68 +4,67 @@ using Microsoft.Extensions.Logging;
using Musify.Application.Configuration;
using Musify.Application.Contracts;
namespace Musify.Infrastructure.Jobs
namespace Musify.Infrastructure.Jobs;
public class TemporalUploadsCleanUpJob(
IServiceScopeFactory scopeFactory,
ILogger<TemporalUploadsCleanUpJob> logger,
ApplicationStorageConfiguration storageConfiguration,
UploadIntentConfiguration uploadIntentConfiguration)
: BackgroundService
{
public class TemporalUploadsCleanUpJob(
IServiceScopeFactory scopeFactory,
ILogger<TemporalUploadsCleanUpJob> logger,
ApplicationStorageConfiguration storageConfiguration,
UploadIntentConfiguration uploadIntentConfiguration)
: BackgroundService
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
logger.LogInformation("TemporalUploadsCleanUpJob started (interval: {Interval}s, prefix: {Prefix})",
uploadIntentConfiguration.TemporalCleanUpJobIntervalSeconds,
uploadIntentConfiguration.TemporalRootPrefix);
using var timer = new PeriodicTimer(TimeSpan.FromSeconds(uploadIntentConfiguration.TemporalCleanUpJobIntervalSeconds));
do
{
logger.LogInformation("TemporalUploadsCleanUpJob started (interval: {Interval}s, prefix: {Prefix} )",
uploadIntentConfiguration.TemporalCleanUpJobIntervalSeconds,
uploadIntentConfiguration.TemporalRootPrefix);
using var timer = new PeriodicTimer(TimeSpan.FromSeconds(uploadIntentConfiguration.TemporalCleanUpJobIntervalSeconds));
do
try
{
try
{
await RunAsync(stoppingToken);
}
catch (Exception exception) when (exception is not OperationCanceledException)
{
logger.LogError(exception, "Error in TemporalUploadsCleanUpJob");
}
await RunAsync(stoppingToken);
}
catch (Exception exception) when (exception is not OperationCanceledException)
{
logger.LogError(exception, "Error in TemporalUploadsCleanUpJob");
}
}
while (await timer.WaitForNextTickAsync(stoppingToken));
}
private async Task RunAsync(CancellationToken cancellationToken)
{
await using var scope = scopeFactory.CreateAsyncScope();
var storageService = scope.ServiceProvider.GetRequiredService<IStorageService>();
var cutOff = DateTime.UtcNow.AddDays(-uploadIntentConfiguration.TemporalUploadsRetentionDays);
var deleted = 0;
var errors = 0;
await foreach (var (key, lastModified) in storageService.ListObjectsAsync(
storageConfiguration.Bucket,
uploadIntentConfiguration.TemporalRootPrefix,
cancellationToken))
{
if (lastModified >= cutOff)
continue;
try
{
await storageService.RemoveFileAsync(storageConfiguration.Bucket, key, cancellationToken);
deleted++;
}
catch (Exception exception)
{
errors++;
logger.LogWarning(exception, "Failed to delete orphaned temp object {Key}", key);
}
while (await timer.WaitForNextTickAsync(stoppingToken));
}
async Task RunAsync(CancellationToken cancellationToken)
{
await using var scope = scopeFactory.CreateAsyncScope();
var storageService = scope.ServiceProvider.GetRequiredService<IStorageService>();
var cutOff = DateTime.UtcNow.AddDays(-uploadIntentConfiguration.TemporalUploadsRetentionDays);
var deleted = 0;
var errors = 0;
await foreach (var (key, lastModified) in storageService.ListObjectsAsync(
storageConfiguration.Bucket,
uploadIntentConfiguration.TemporalRootPrefix,
cancellationToken))
{
if (lastModified >= cutOff)
continue;
try
{
await storageService.RemoveFileAsync(storageConfiguration.Bucket, key, cancellationToken);
deleted++;
}
catch (Exception exception)
{
errors++;
logger.LogWarning(exception, "Failed to delete orphaned temp object {Key}", key);
}
}
if (deleted > 0 || errors > 0)
logger.LogInformation("TemporalUploadsCleanUpJob: deleted {Deleted} orphaned objects, {Errors} errors", deleted, errors);
}
if (deleted > 0 || errors > 0)
logger.LogInformation("TemporalUploadsCleanUpJob: deleted {Deleted} orphaned objects, {Errors} errors", deleted, errors);
}
}
@@ -3,71 +3,70 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Musify.Application.Configuration;
using Musify.Domain.ValueObjects;
using Musify.Application.Contracts;
using Musify.Domain.ValueObjects;
namespace Musify.Infrastructure.Jobs
namespace Musify.Infrastructure.Jobs;
public class UploadIntentExpirationJob(
IServiceScopeFactory scopeFactory,
ILogger<UploadIntentExpirationJob> logger,
UploadIntentConfiguration uploadIntentConfiguration)
: BackgroundService
{
public class UploadIntentExpirationJob(
IServiceScopeFactory scopeFactory,
ILogger<UploadIntentExpirationJob> logger,
UploadIntentConfiguration uploadIntentConfiguration)
: BackgroundService
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
logger.LogInformation("UploadIntentExpirationJob started (interval: {Interval}s)", uploadIntentConfiguration.ExpirationJobIntervalSeconds);
using var timer = new PeriodicTimer(TimeSpan.FromSeconds(uploadIntentConfiguration.ExpirationJobIntervalSeconds));
do
{
logger.LogInformation("UploadIntentExpirationJob started (interval: {Interval}s)", uploadIntentConfiguration.ExpirationJobIntervalSeconds);
using var timer = new PeriodicTimer(TimeSpan.FromSeconds(uploadIntentConfiguration.ExpirationJobIntervalSeconds));
do
try
{
try
{
await RunAsync(stoppingToken);
}
catch (Exception exception) when (exception is not OperationCanceledException)
{
logger.LogError(exception, "Error in UploadIntentExpirationJob");
}
await RunAsync(stoppingToken);
}
while (await timer.WaitForNextTickAsync(stoppingToken));
catch (Exception exception) when (exception is not OperationCanceledException)
{
logger.LogError(exception, "Error in UploadIntentExpirationJob");
}
}
while (await timer.WaitForNextTickAsync(stoppingToken));
}
private async Task RunAsync(CancellationToken cancellationToken)
{
await using var scope = scopeFactory.CreateAsyncScope();
var database = scope.ServiceProvider.GetRequiredService<IDatabase>();
var now = DateTime.UtcNow;
var expiredIntents = await database.UploadIntents
.Where(i => i.Status == UploadIntentStatus.Issued && i.ExpiresAt < now)
.ToListAsync(cancellationToken);
if (expiredIntents.Count > 0)
{
foreach (var intent in expiredIntents)
intent.Status = UploadIntentStatus.Expired;
await database.SaveChangesAsync(cancellationToken);
logger.LogInformation("Marked {Count} upload intents as Expired", expiredIntents.Count);
}
async Task RunAsync(CancellationToken cancellationToken)
if (uploadIntentConfiguration.ExpiredIntentsRetentionDays >= 0)
{
await using var scope = scopeFactory.CreateAsyncScope();
var database = scope.ServiceProvider.GetRequiredService<IDatabase>();
var retentionCutoff = now.AddDays(-uploadIntentConfiguration.ExpiredIntentsRetentionDays);
var now = DateTime.UtcNow;
var expiredIntents = await database.UploadIntents
.Where(i => i.Status == UploadIntentStatus.Issued && i.ExpiresAt < now)
var oldExpiredIntents = await database.UploadIntents
.Where(i => i.Status == UploadIntentStatus.Expired && i.ExpiresAt < retentionCutoff)
.ToListAsync(cancellationToken);
if (expiredIntents.Count > 0)
if (oldExpiredIntents.Count > 0)
{
foreach (var intent in expiredIntents)
intent.Status = UploadIntentStatus.Expired;
database.UploadIntents.RemoveRange(oldExpiredIntents);
await database.SaveChangesAsync(cancellationToken);
logger.LogInformation("Marked {Count} upload intents as Expired", expiredIntents.Count);
}
if (uploadIntentConfiguration.ExpiredIntentsRetentionDays >= 0)
{
var retentionCutoff = now.AddDays(-uploadIntentConfiguration.ExpiredIntentsRetentionDays);
var oldExpiredIntents = await database.UploadIntents
.Where(i => i.Status == UploadIntentStatus.Expired && i.ExpiresAt < retentionCutoff)
.ToListAsync(cancellationToken);
if (oldExpiredIntents.Count > 0)
{
database.UploadIntents.RemoveRange(oldExpiredIntents);
await database.SaveChangesAsync(cancellationToken);
logger.LogInformation("Deleted {Count} old Expired upload intents past retention window", oldExpiredIntents.Count);
}
logger.LogInformation("Deleted {Count} old Expired upload intents past retention window", oldExpiredIntents.Count);
}
}
}