diff --git a/MareSynchronosServer/MareSynchronosServer/SystemInfoService.cs b/MareSynchronosServer/MareSynchronosServer/SystemInfoService.cs index c8b8e85..670c5e9 100644 --- a/MareSynchronosServer/MareSynchronosServer/SystemInfoService.cs +++ b/MareSynchronosServer/MareSynchronosServer/SystemInfoService.cs @@ -16,14 +16,16 @@ namespace MareSynchronosServer; public class SystemInfoService : IHostedService, IDisposable { + private readonly MetricsService.MetricsServiceClient metricsClient; private readonly IServiceProvider _services; private readonly ILogger _logger; private readonly IHubContext _hubContext; private Timer _timer; public SystemInfoDto SystemInfoDto { get; private set; } = new(); - public SystemInfoService(IServiceProvider services, ILogger logger, IHubContext hubContext) + public SystemInfoService(MetricsService.MetricsServiceClient metricsClient, IServiceProvider services, ILogger logger, IHubContext hubContext) { + this.metricsClient = metricsClient; _services = services; _logger = logger; _hubContext = hubContext; @@ -46,10 +48,9 @@ public class SystemInfoService : IHostedService, IDisposable using var scope = _services.CreateScope(); using var db = scope.ServiceProvider.GetService()!; - var metricsServiceClient = scope.ServiceProvider.GetService()!; - _ = metricsServiceClient.SetGauge(new SetGaugeRequest() + metricsClient.SetGauge(new SetGaugeRequest() { GaugeName = MetricsAPI.GaugeAvailableWorkerThreads, Value = workerThreads }); - _ = metricsServiceClient.SetGauge(new SetGaugeRequest() + metricsClient.SetGauge(new SetGaugeRequest() { GaugeName = MetricsAPI.GaugeAvailableIOWorkerThreads, Value = ioThreads }); var users = db.Users.Count(c => c.CharacterIdentification != null); diff --git a/MareSynchronosServer/MareSynchronosServices/CleanupService.cs b/MareSynchronosServer/MareSynchronosServices/CleanupService.cs index c21ea73..7d527fc 100644 --- a/MareSynchronosServer/MareSynchronosServices/CleanupService.cs +++ b/MareSynchronosServer/MareSynchronosServices/CleanupService.cs @@ -46,76 +46,9 @@ namespace MareSynchronosServices private void CleanUp(object state) { - if (!int.TryParse(_configuration["UnusedFileRetentionPeriodInDays"], out var filesOlderThanDays)) - { - filesOlderThanDays = 7; - } - using var scope = _services.CreateScope(); using var dbContext = scope.ServiceProvider.GetService()!; - _logger.LogInformation("Cleaning up files older than {filesOlderThanDays} days", filesOlderThanDays); - - try - { - var prevTime = DateTime.Now.Subtract(TimeSpan.FromDays(filesOlderThanDays)); - - var allFiles = dbContext.Files.ToList(); - var cachedir = _configuration["CacheDirectory"]; - foreach (var file in allFiles.Where(f => f.Uploaded)) - { - var fileName = Path.Combine(cachedir, file.Hash); - var fi = new FileInfo(fileName); - if (!fi.Exists) - { - _logger.LogInformation("File does not exist anymore: {fileName}", fileName); - dbContext.Files.Remove(file); - } - else if (fi.LastAccessTime < prevTime) - { - metrics.DecGaugeBy(MetricsAPI.GaugeFilesTotalSize, fi.Length); - metrics.DecGaugeBy(MetricsAPI.GaugeFilesTotal, 1); - _logger.LogInformation("File outdated: {fileName}", fileName); - dbContext.Files.Remove(file); - fi.Delete(); - } - } - } - catch (Exception ex) - { - _logger.LogWarning(ex, "Error during file cleanup"); - } - - var cacheSizeLimitInGiB = _configuration.GetValue("CacheSizeHardLimitInGiB", -1); - - try - { - if (cacheSizeLimitInGiB > 0) - { - _logger.LogInformation("Cleaning up files beyond the cache size limit"); - var allLocalFiles = Directory.EnumerateFiles(_configuration["CacheDirectory"]).Select(f => new FileInfo(f)).ToList().OrderBy(f => f.LastAccessTimeUtc).ToList(); - var totalCacheSizeInBytes = allLocalFiles.Sum(s => s.Length); - long cacheSizeLimitInBytes = (long)(cacheSizeLimitInGiB * 1024 * 1024 * 1024); - HashSet removedHashes = new(); - while (totalCacheSizeInBytes > cacheSizeLimitInBytes && allLocalFiles.Any()) - { - var oldestFile = allLocalFiles.First(); - removedHashes.Add(oldestFile.Name.ToLower()); - allLocalFiles.Remove(oldestFile); - totalCacheSizeInBytes -= oldestFile.Length; - metrics.DecGaugeBy(MetricsAPI.GaugeFilesTotalSize, oldestFile.Length); - metrics.DecGaugeBy(MetricsAPI.GaugeFilesTotal, 1); - oldestFile.Delete(); - } - - dbContext.Files.RemoveRange(dbContext.Files.Where(f => removedHashes.Contains(f.Hash.ToLower()))); - } - } - catch (Exception ex) - { - _logger.LogWarning(ex, "Error during cache size limit cleanup"); - } - try { _logger.LogInformation($"Cleaning up expired lodestone authentications"); @@ -129,7 +62,7 @@ namespace MareSynchronosServices } } - dbContext.RemoveRange(expiredAuths.Select(a => a.User)); + dbContext.Users.RemoveRange(expiredAuths.Where(u => u.User != null).Select(a => a.User)); dbContext.RemoveRange(expiredAuths); } catch (Exception ex) diff --git a/MareSynchronosServer/MareSynchronosServices/MareSynchronosServices.csproj b/MareSynchronosServer/MareSynchronosServices/MareSynchronosServices.csproj index 6dcbfc0..d599959 100644 --- a/MareSynchronosServer/MareSynchronosServices/MareSynchronosServices.csproj +++ b/MareSynchronosServer/MareSynchronosServices/MareSynchronosServices.csproj @@ -8,6 +8,7 @@ + diff --git a/MareSynchronosServer/MareSynchronosServices/Metrics/MareMetrics.cs b/MareSynchronosServer/MareSynchronosServices/Metrics/MareMetrics.cs index 88467f5..8abe97e 100644 --- a/MareSynchronosServer/MareSynchronosServices/Metrics/MareMetrics.cs +++ b/MareSynchronosServer/MareSynchronosServices/Metrics/MareMetrics.cs @@ -11,7 +11,7 @@ namespace MareSynchronosServices.Metrics; public class MareMetrics { - public MareMetrics(IServiceProvider services, IConfiguration configuration) + public MareMetrics(IServiceProvider services) { using var scope = services.CreateScope(); using var dbContext = scope.ServiceProvider.GetService(); @@ -36,14 +36,14 @@ public class MareMetrics private readonly Dictionary gauges = new() { { MetricsAPI.GaugeConnections, Prometheus.Metrics.CreateGauge(MetricsAPI.GaugeConnections, "Unauthorized Connections") }, - { MetricsAPI.GaugeAuthorizedConnections, Prometheus.Metrics.CreateGauge(MetricsAPI.GaugeConnections, "Authorized Connections") }, - { MetricsAPI.GaugeAvailableIOWorkerThreads, Prometheus.Metrics.CreateGauge(MetricsAPI.GaugeConnections, "Available Threadpool IO Workers") }, - { MetricsAPI.GaugeAvailableWorkerThreads, Prometheus.Metrics.CreateGauge(MetricsAPI.GaugeConnections, "Aavailable Threadpool Workers") }, - { MetricsAPI.GaugeUsersRegistered, Prometheus.Metrics.CreateGauge(MetricsAPI.GaugeConnections, "Total Registrations") }, - { MetricsAPI.GaugePairs, Prometheus.Metrics.CreateGauge(MetricsAPI.GaugeConnections, "Total Pairs") }, - { MetricsAPI.GaugePairsPaused, Prometheus.Metrics.CreateGauge(MetricsAPI.GaugeConnections, "Total Paused Pairs") }, - { MetricsAPI.GaugeFilesTotal, Prometheus.Metrics.CreateGauge(MetricsAPI.GaugeConnections, "Total uploaded files") }, - { MetricsAPI.GaugeFilesTotalSize, Prometheus.Metrics.CreateGauge(MetricsAPI.GaugeConnections, "Total uploaded files (bytes)") }, + { MetricsAPI.GaugeAuthorizedConnections, Prometheus.Metrics.CreateGauge(MetricsAPI.GaugeAuthorizedConnections, "Authorized Connections") }, + { MetricsAPI.GaugeAvailableIOWorkerThreads, Prometheus.Metrics.CreateGauge(MetricsAPI.GaugeAvailableIOWorkerThreads, "Available Threadpool IO Workers") }, + { MetricsAPI.GaugeAvailableWorkerThreads, Prometheus.Metrics.CreateGauge(MetricsAPI.GaugeAvailableWorkerThreads, "Aavailable Threadpool Workers") }, + { MetricsAPI.GaugeUsersRegistered, Prometheus.Metrics.CreateGauge(MetricsAPI.GaugeUsersRegistered, "Total Registrations") }, + { MetricsAPI.GaugePairs, Prometheus.Metrics.CreateGauge(MetricsAPI.GaugePairs, "Total Pairs") }, + { MetricsAPI.GaugePairsPaused, Prometheus.Metrics.CreateGauge(MetricsAPI.GaugePairsPaused, "Total Paused Pairs") }, + { MetricsAPI.GaugeFilesTotal, Prometheus.Metrics.CreateGauge(MetricsAPI.GaugeFilesTotal, "Total uploaded files") }, + { MetricsAPI.GaugeFilesTotalSize, Prometheus.Metrics.CreateGauge(MetricsAPI.GaugeFilesTotalSize, "Total uploaded files (bytes)") }, }; public void SetGaugeTo(string gaugeName, double value) diff --git a/MareSynchronosServer/MareSynchronosStaticFilesServer/CleanupService.cs b/MareSynchronosServer/MareSynchronosStaticFilesServer/CleanupService.cs index e2125b4..6c4f489 100644 --- a/MareSynchronosServer/MareSynchronosStaticFilesServer/CleanupService.cs +++ b/MareSynchronosServer/MareSynchronosStaticFilesServer/CleanupService.cs @@ -1,5 +1,6 @@ using MareSynchronosShared.Data; using MareSynchronosShared.Metrics; +using MareSynchronosShared.Protos; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; @@ -10,38 +11,50 @@ using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; -using static MareSynchronosShared.Protos.MetricsService; namespace MareSynchronosStaticFilesServer; public class CleanupService : IHostedService, IDisposable { - private readonly MetricsServiceClient _metrics; + private readonly MetricsService.MetricsServiceClient _metrics; private readonly ILogger _logger; private readonly IServiceProvider _services; private readonly IConfiguration _configuration; private Timer? _timer; - public CleanupService(MetricsServiceClient metrics, ILogger logger, IServiceProvider services, IConfiguration configuration) + public CleanupService(MetricsService.MetricsServiceClient metrics, ILogger logger, IServiceProvider services, IConfiguration configuration) { _metrics = metrics; _logger = logger; _services = services; _configuration = configuration.GetRequiredSection("MareSynchronos"); - metrics.SetGauge(new MareSynchronosShared.Protos.SetGaugeRequest() - { - GaugeName = MetricsAPI.GaugeFilesTotalSize, - Value = Directory.EnumerateFiles(_configuration["CacheDirectory"]).Sum(f => new FileInfo(f).Length) - }); } - public Task StartAsync(CancellationToken cancellationToken) + public async Task StartAsync(CancellationToken cancellationToken) { _logger.LogInformation("Cleanup Service started"); - _timer = new Timer(CleanUp, null, TimeSpan.Zero, TimeSpan.FromMinutes(10)); + _ = Task.Run(async () => + { + _logger.LogInformation("Calculating initial files"); - return Task.CompletedTask; + DirectoryInfo dir = new DirectoryInfo(_configuration["CacheDirectory"]); + var allFiles = dir.GetFiles(); + await _metrics.SetGaugeAsync(new SetGaugeRequest() + { + GaugeName = MetricsAPI.GaugeFilesTotalSize, + Value = allFiles.Sum(f => f.Length) + }); + await _metrics.SetGaugeAsync(new SetGaugeRequest() + { + GaugeName = MetricsAPI.GaugeFilesTotal, + Value = allFiles.Length + }); + + _logger.LogInformation("Initial file calculation finished, starting periodic cleanup task"); + + _timer = new Timer(CleanUp, null, TimeSpan.FromSeconds(15), TimeSpan.FromMinutes(10)); + }); } private void CleanUp(object? state) @@ -81,13 +94,17 @@ public class CleanupService : IHostedService, IDisposable } } - foreach (var file in Directory.EnumerateFiles(cachedir).ToList()) + var allFilesHashes = new HashSet(allFiles.Select(a => a.Hash.ToUpperInvariant())); + DirectoryInfo dir = new DirectoryInfo(cachedir); + var allFilesInDir = dir.GetFiles(); + foreach (var file in allFilesInDir) { - FileInfo fi = new(file); - if (!allFiles.Any(f => f.Hash == fi.Name.ToUpperInvariant())) + if (!allFilesHashes.Contains(file.Name.ToUpperInvariant())) { - fi.Delete(); - _logger.LogInformation("File not in DB, deleting: {fileName}", fi.FullName); + _metrics.DecGauge(new() { GaugeName = MetricsAPI.GaugeFilesTotalSize, Value = file.Length }); + _metrics.DecGauge(new() { GaugeName = MetricsAPI.GaugeFilesTotal, Value = 1 }); + file.Delete(); + _logger.LogInformation("File not in DB, deleting: {fileName}", file.FullName); } } } diff --git a/MareSynchronosServer/MareSynchronosStaticFilesServer/MareSynchronosStaticFilesServer.csproj b/MareSynchronosServer/MareSynchronosStaticFilesServer/MareSynchronosStaticFilesServer.csproj index 7a4c93b..583a211 100644 --- a/MareSynchronosServer/MareSynchronosStaticFilesServer/MareSynchronosStaticFilesServer.csproj +++ b/MareSynchronosServer/MareSynchronosStaticFilesServer/MareSynchronosStaticFilesServer.csproj @@ -7,6 +7,7 @@ + diff --git a/MareSynchronosServer/MareSynchronosStaticFilesServer/Startup.cs b/MareSynchronosServer/MareSynchronosStaticFilesServer/Startup.cs index 5ca1ad8..40edd0e 100644 --- a/MareSynchronosServer/MareSynchronosStaticFilesServer/Startup.cs +++ b/MareSynchronosServer/MareSynchronosStaticFilesServer/Startup.cs @@ -48,6 +48,8 @@ public class Startup options.EnableThreadSafetyChecks(false); }, mareSettings.GetValue("DbContextPoolSize", 1024)); + services.AddHostedService(); + services.AddAuthentication(options => { options.DefaultScheme = SecretKeyGrpcAuthenticationHandler.AuthScheme;