Files
UnrealEngine/Engine/Source/Programs/UnrealCloudDDC/Jupiter/Implementation/GC/RefCleanupService.cs
2025-05-18 13:04:45 +08:00

92 lines
2.3 KiB
C#

// Copyright Epic Games, Inc. All Rights Reserved.
using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
namespace Jupiter.Implementation
{
public class RefCleanupState
{
public RefCleanupState(IRefCleanup refCleanup)
{
RefCleanup = refCleanup;
}
public IRefCleanup RefCleanup { get; }
public Task? RunningCleanupTask { get; set; } = null;
}
public class RefCleanupService : PollingService<RefCleanupState>
{
private readonly IOptionsMonitor<GCSettings> _settings;
private readonly ILeaderElection _leaderElection;
private volatile bool _alreadyPolling;
private readonly ILogger _logger;
public RefCleanupService(IOptionsMonitor<GCSettings> settings, IRefCleanup refCleanup, ILeaderElection leaderElection, ILogger<RefCleanupService> logger) : base(serviceName: nameof(RefCleanupService), settings.CurrentValue.RefCleanupPollFrequency, new RefCleanupState(refCleanup), logger, startAtRandomTime: false)
{
_settings = settings;
_leaderElection = leaderElection;
_logger = logger;
}
protected override bool ShouldStartPolling()
{
return _settings.CurrentValue.CleanOldRefRecords;
}
public override async Task<bool> OnPollAsync(RefCleanupState state, CancellationToken cancellationToken)
{
if (_alreadyPolling)
{
return false;
}
_alreadyPolling = true;
try
{
if (!_leaderElection.IsThisInstanceLeader())
{
_logger.LogInformation("Skipped ref cleanup run as this instance was not the leader");
return false;
}
if (!state.RunningCleanupTask?.IsCompleted ?? false)
{
return false;
}
if (state.RunningCleanupTask != null)
{
await state.RunningCleanupTask;
}
state.RunningCleanupTask = DoCleanupAsync(state, cancellationToken);
return true;
}
finally
{
_alreadyPolling = false;
}
}
private async Task DoCleanupAsync(RefCleanupState state, CancellationToken cancellationToken)
{
_logger.LogInformation("Attempting to run Refs Cleanup. ");
try
{
int countOfRemovedRecords = await state.RefCleanup.Cleanup(cancellationToken);
_logger.LogInformation("Ran Refs Cleanup. Deleted {CountRefRecords}", countOfRemovedRecords);
}
catch (Exception e)
{
_logger.LogError("Error running Refs Cleanup. {Exception}", e);
}
}
}
}