mirror of
https://github.com/Cleanuparr/Cleanuparr.git
synced 2026-10-28 10:48:49 -04:00
123 lines
4.3 KiB
C#
123 lines
4.3 KiB
C#
using Cleanuparr.Domain.Enums;
|
|
using Cleanuparr.Infrastructure.Features.Context;
|
|
using Cleanuparr.Infrastructure.Features.DryRun;
|
|
using Cleanuparr.Infrastructure.Features.Jobs;
|
|
using Cleanuparr.Infrastructure.Helpers;
|
|
using Cleanuparr.Api.Hubs;
|
|
using Cleanuparr.Infrastructure.Interceptors;
|
|
using Cleanuparr.Infrastructure.Models;
|
|
using Cleanuparr.Infrastructure.Services.Interfaces;
|
|
using Cleanuparr.Persistence;
|
|
using Cleanuparr.Persistence.Models.State;
|
|
using Microsoft.AspNetCore.SignalR;
|
|
using Quartz;
|
|
using Serilog.Context;
|
|
|
|
namespace Cleanuparr.Api.Jobs;
|
|
|
|
[DisallowConcurrentExecution]
|
|
public sealed class GenericJob<T> : IJob
|
|
where T : IHandler
|
|
{
|
|
private readonly ILogger<GenericJob<T>> _logger;
|
|
private readonly IServiceScopeFactory _scopeFactory;
|
|
private readonly TimeProvider _timeProvider;
|
|
private readonly DryRunActivity _dryRunActivity;
|
|
|
|
public GenericJob(
|
|
ILogger<GenericJob<T>> logger,
|
|
IServiceScopeFactory scopeFactory,
|
|
TimeProvider timeProvider,
|
|
DryRunActivity dryRunActivity)
|
|
{
|
|
_logger = logger;
|
|
_scopeFactory = scopeFactory;
|
|
_timeProvider = timeProvider;
|
|
_dryRunActivity = dryRunActivity;
|
|
}
|
|
|
|
public async Task Execute(IJobExecutionContext context)
|
|
{
|
|
using var _ = LogContext.PushProperty("JobName", typeof(T).Name);
|
|
|
|
Guid jobRunId = Guid.CreateVersion7();
|
|
JobType jobType = Enum.Parse<JobType>(typeof(T).Name);
|
|
JobRunStatus? status = null;
|
|
bool trackedDryRun = false;
|
|
|
|
try
|
|
{
|
|
await using var scope = _scopeFactory.CreateAsyncScope();
|
|
var eventsContext = scope.ServiceProvider.GetRequiredService<EventsContext>();
|
|
var hubContext = scope.ServiceProvider.GetRequiredService<IHubContext<AppHub>>();
|
|
var jobManagementService = scope.ServiceProvider.GetRequiredService<IJobManagementService>();
|
|
var dryRunInterceptor = scope.ServiceProvider.GetRequiredService<IDryRunInterceptor>();
|
|
|
|
var jobRun = new JobRun { Id = jobRunId, Type = jobType };
|
|
eventsContext.JobRuns.Add(jobRun);
|
|
await eventsContext.SaveChangesAsync();
|
|
|
|
ContextProvider.SetJobRunId(jobRunId);
|
|
bool isDryRun = await dryRunInterceptor.IsDryRunEnabled();
|
|
ContextProvider.SetDryRun(isDryRun);
|
|
|
|
if (isDryRun)
|
|
{
|
|
await _dryRunActivity.EnterAsync();
|
|
trackedDryRun = true;
|
|
}
|
|
|
|
using var __ = LogContext.PushProperty(LogProperties.JobRunId, jobRunId.ToString());
|
|
|
|
await BroadcastJobStatus(hubContext, jobManagementService, jobType, false);
|
|
|
|
var handler = scope.ServiceProvider.GetRequiredService<T>();
|
|
await handler.ExecuteAsync(context.CancellationToken);
|
|
|
|
status = JobRunStatus.Completed;
|
|
await BroadcastJobStatus(hubContext, jobManagementService, jobType, true);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "{name} failed", typeof(T).Name);
|
|
status = JobRunStatus.Failed;
|
|
}
|
|
finally
|
|
{
|
|
// Exit first so a failed job-run save can't leave the count stuck.
|
|
if (trackedDryRun)
|
|
{
|
|
_dryRunActivity.Exit();
|
|
}
|
|
|
|
await using var finalScope = _scopeFactory.CreateAsyncScope();
|
|
var eventsContext = finalScope.ServiceProvider.GetRequiredService<EventsContext>();
|
|
var jobRun = await eventsContext.JobRuns.FindAsync(jobRunId);
|
|
if (jobRun is not null)
|
|
{
|
|
jobRun.CompletedAt = _timeProvider.GetUtcNow();
|
|
jobRun.Status = status;
|
|
await eventsContext.SaveChangesAsync();
|
|
}
|
|
}
|
|
}
|
|
|
|
private async Task BroadcastJobStatus(IHubContext<AppHub> hubContext, IJobManagementService jobManagementService, JobType jobType, bool isFinished)
|
|
{
|
|
try
|
|
{
|
|
JobInfo jobInfo = await jobManagementService.GetJob(jobType);
|
|
|
|
if (isFinished)
|
|
{
|
|
jobInfo.Status = "Scheduled";
|
|
}
|
|
|
|
await hubContext.Clients.All.SendAsync("JobStatusUpdate", jobInfo);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Failed to broadcast job status update");
|
|
}
|
|
}
|
|
} |