fixes etc
This commit is contained in:
@@ -16,14 +16,16 @@ namespace MareSynchronosServer;
|
|||||||
|
|
||||||
public class SystemInfoService : IHostedService, IDisposable
|
public class SystemInfoService : IHostedService, IDisposable
|
||||||
{
|
{
|
||||||
|
private readonly MetricsService.MetricsServiceClient metricsClient;
|
||||||
private readonly IServiceProvider _services;
|
private readonly IServiceProvider _services;
|
||||||
private readonly ILogger<SystemInfoService> _logger;
|
private readonly ILogger<SystemInfoService> _logger;
|
||||||
private readonly IHubContext<MareHub> _hubContext;
|
private readonly IHubContext<MareHub> _hubContext;
|
||||||
private Timer _timer;
|
private Timer _timer;
|
||||||
public SystemInfoDto SystemInfoDto { get; private set; } = new();
|
public SystemInfoDto SystemInfoDto { get; private set; } = new();
|
||||||
|
|
||||||
public SystemInfoService(IServiceProvider services, ILogger<SystemInfoService> logger, IHubContext<MareHub> hubContext)
|
public SystemInfoService(MetricsService.MetricsServiceClient metricsClient, IServiceProvider services, ILogger<SystemInfoService> logger, IHubContext<MareHub> hubContext)
|
||||||
{
|
{
|
||||||
|
this.metricsClient = metricsClient;
|
||||||
_services = services;
|
_services = services;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_hubContext = hubContext;
|
_hubContext = hubContext;
|
||||||
@@ -46,10 +48,9 @@ public class SystemInfoService : IHostedService, IDisposable
|
|||||||
using var scope = _services.CreateScope();
|
using var scope = _services.CreateScope();
|
||||||
using var db = scope.ServiceProvider.GetService<MareDbContext>()!;
|
using var db = scope.ServiceProvider.GetService<MareDbContext>()!;
|
||||||
|
|
||||||
var metricsServiceClient = scope.ServiceProvider.GetService<MetricsService.MetricsServiceClient>()!;
|
metricsClient.SetGauge(new SetGaugeRequest()
|
||||||
_ = metricsServiceClient.SetGauge(new SetGaugeRequest()
|
|
||||||
{ GaugeName = MetricsAPI.GaugeAvailableWorkerThreads, Value = workerThreads });
|
{ GaugeName = MetricsAPI.GaugeAvailableWorkerThreads, Value = workerThreads });
|
||||||
_ = metricsServiceClient.SetGauge(new SetGaugeRequest()
|
metricsClient.SetGauge(new SetGaugeRequest()
|
||||||
{ GaugeName = MetricsAPI.GaugeAvailableIOWorkerThreads, Value = ioThreads });
|
{ GaugeName = MetricsAPI.GaugeAvailableIOWorkerThreads, Value = ioThreads });
|
||||||
|
|
||||||
var users = db.Users.Count(c => c.CharacterIdentification != null);
|
var users = db.Users.Count(c => c.CharacterIdentification != null);
|
||||||
|
|||||||
@@ -46,76 +46,9 @@ namespace MareSynchronosServices
|
|||||||
|
|
||||||
private void CleanUp(object state)
|
private void CleanUp(object state)
|
||||||
{
|
{
|
||||||
if (!int.TryParse(_configuration["UnusedFileRetentionPeriodInDays"], out var filesOlderThanDays))
|
|
||||||
{
|
|
||||||
filesOlderThanDays = 7;
|
|
||||||
}
|
|
||||||
|
|
||||||
using var scope = _services.CreateScope();
|
using var scope = _services.CreateScope();
|
||||||
using var dbContext = scope.ServiceProvider.GetService<MareDbContext>()!;
|
using var dbContext = scope.ServiceProvider.GetService<MareDbContext>()!;
|
||||||
|
|
||||||
_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<double>("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<string> 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
|
try
|
||||||
{
|
{
|
||||||
_logger.LogInformation($"Cleaning up expired lodestone authentications");
|
_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);
|
dbContext.RemoveRange(expiredAuths);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
<PackageReference Include="Discord.Net" Version="3.7.2" />
|
<PackageReference Include="Discord.Net" Version="3.7.2" />
|
||||||
<PackageReference Include="EFCore.NamingConventions" Version="6.0.0" />
|
<PackageReference Include="EFCore.NamingConventions" Version="6.0.0" />
|
||||||
<PackageReference Include="Grpc.AspNetCore" Version="2.47.0" />
|
<PackageReference Include="Grpc.AspNetCore" Version="2.47.0" />
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="6.0.8" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Hosting.Systemd" Version="6.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Hosting.Systemd" Version="6.0.0" />
|
||||||
<PackageReference Include="prometheus-net.AspNetCore" Version="6.0.0" />
|
<PackageReference Include="prometheus-net.AspNetCore" Version="6.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ namespace MareSynchronosServices.Metrics;
|
|||||||
|
|
||||||
public class MareMetrics
|
public class MareMetrics
|
||||||
{
|
{
|
||||||
public MareMetrics(IServiceProvider services, IConfiguration configuration)
|
public MareMetrics(IServiceProvider services)
|
||||||
{
|
{
|
||||||
using var scope = services.CreateScope();
|
using var scope = services.CreateScope();
|
||||||
using var dbContext = scope.ServiceProvider.GetService<MareDbContext>();
|
using var dbContext = scope.ServiceProvider.GetService<MareDbContext>();
|
||||||
@@ -36,14 +36,14 @@ public class MareMetrics
|
|||||||
private readonly Dictionary<string, Gauge> gauges = new()
|
private readonly Dictionary<string, Gauge> gauges = new()
|
||||||
{
|
{
|
||||||
{ MetricsAPI.GaugeConnections, Prometheus.Metrics.CreateGauge(MetricsAPI.GaugeConnections, "Unauthorized Connections") },
|
{ MetricsAPI.GaugeConnections, Prometheus.Metrics.CreateGauge(MetricsAPI.GaugeConnections, "Unauthorized Connections") },
|
||||||
{ MetricsAPI.GaugeAuthorizedConnections, Prometheus.Metrics.CreateGauge(MetricsAPI.GaugeConnections, "Authorized Connections") },
|
{ MetricsAPI.GaugeAuthorizedConnections, Prometheus.Metrics.CreateGauge(MetricsAPI.GaugeAuthorizedConnections, "Authorized Connections") },
|
||||||
{ MetricsAPI.GaugeAvailableIOWorkerThreads, Prometheus.Metrics.CreateGauge(MetricsAPI.GaugeConnections, "Available Threadpool IO Workers") },
|
{ MetricsAPI.GaugeAvailableIOWorkerThreads, Prometheus.Metrics.CreateGauge(MetricsAPI.GaugeAvailableIOWorkerThreads, "Available Threadpool IO Workers") },
|
||||||
{ MetricsAPI.GaugeAvailableWorkerThreads, Prometheus.Metrics.CreateGauge(MetricsAPI.GaugeConnections, "Aavailable Threadpool Workers") },
|
{ MetricsAPI.GaugeAvailableWorkerThreads, Prometheus.Metrics.CreateGauge(MetricsAPI.GaugeAvailableWorkerThreads, "Aavailable Threadpool Workers") },
|
||||||
{ MetricsAPI.GaugeUsersRegistered, Prometheus.Metrics.CreateGauge(MetricsAPI.GaugeConnections, "Total Registrations") },
|
{ MetricsAPI.GaugeUsersRegistered, Prometheus.Metrics.CreateGauge(MetricsAPI.GaugeUsersRegistered, "Total Registrations") },
|
||||||
{ MetricsAPI.GaugePairs, Prometheus.Metrics.CreateGauge(MetricsAPI.GaugeConnections, "Total Pairs") },
|
{ MetricsAPI.GaugePairs, Prometheus.Metrics.CreateGauge(MetricsAPI.GaugePairs, "Total Pairs") },
|
||||||
{ MetricsAPI.GaugePairsPaused, Prometheus.Metrics.CreateGauge(MetricsAPI.GaugeConnections, "Total Paused Pairs") },
|
{ MetricsAPI.GaugePairsPaused, Prometheus.Metrics.CreateGauge(MetricsAPI.GaugePairsPaused, "Total Paused Pairs") },
|
||||||
{ MetricsAPI.GaugeFilesTotal, Prometheus.Metrics.CreateGauge(MetricsAPI.GaugeConnections, "Total uploaded files") },
|
{ MetricsAPI.GaugeFilesTotal, Prometheus.Metrics.CreateGauge(MetricsAPI.GaugeFilesTotal, "Total uploaded files") },
|
||||||
{ MetricsAPI.GaugeFilesTotalSize, Prometheus.Metrics.CreateGauge(MetricsAPI.GaugeConnections, "Total uploaded files (bytes)") },
|
{ MetricsAPI.GaugeFilesTotalSize, Prometheus.Metrics.CreateGauge(MetricsAPI.GaugeFilesTotalSize, "Total uploaded files (bytes)") },
|
||||||
};
|
};
|
||||||
|
|
||||||
public void SetGaugeTo(string gaugeName, double value)
|
public void SetGaugeTo(string gaugeName, double value)
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using MareSynchronosShared.Data;
|
using MareSynchronosShared.Data;
|
||||||
using MareSynchronosShared.Metrics;
|
using MareSynchronosShared.Metrics;
|
||||||
|
using MareSynchronosShared.Protos;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Hosting;
|
using Microsoft.Extensions.Hosting;
|
||||||
@@ -10,38 +11,50 @@ using System.IO;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using static MareSynchronosShared.Protos.MetricsService;
|
|
||||||
|
|
||||||
namespace MareSynchronosStaticFilesServer;
|
namespace MareSynchronosStaticFilesServer;
|
||||||
|
|
||||||
public class CleanupService : IHostedService, IDisposable
|
public class CleanupService : IHostedService, IDisposable
|
||||||
{
|
{
|
||||||
private readonly MetricsServiceClient _metrics;
|
private readonly MetricsService.MetricsServiceClient _metrics;
|
||||||
private readonly ILogger<CleanupService> _logger;
|
private readonly ILogger<CleanupService> _logger;
|
||||||
private readonly IServiceProvider _services;
|
private readonly IServiceProvider _services;
|
||||||
private readonly IConfiguration _configuration;
|
private readonly IConfiguration _configuration;
|
||||||
private Timer? _timer;
|
private Timer? _timer;
|
||||||
|
|
||||||
public CleanupService(MetricsServiceClient metrics, ILogger<CleanupService> logger, IServiceProvider services, IConfiguration configuration)
|
public CleanupService(MetricsService.MetricsServiceClient metrics, ILogger<CleanupService> logger, IServiceProvider services, IConfiguration configuration)
|
||||||
{
|
{
|
||||||
_metrics = metrics;
|
_metrics = metrics;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_services = services;
|
_services = services;
|
||||||
_configuration = configuration.GetRequiredSection("MareSynchronos");
|
_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");
|
_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)
|
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<string>(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 (!allFilesHashes.Contains(file.Name.ToUpperInvariant()))
|
||||||
if (!allFiles.Any(f => f.Hash == fi.Name.ToUpperInvariant()))
|
|
||||||
{
|
{
|
||||||
fi.Delete();
|
_metrics.DecGauge(new() { GaugeName = MetricsAPI.GaugeFilesTotalSize, Value = file.Length });
|
||||||
_logger.LogInformation("File not in DB, deleting: {fileName}", fi.FullName);
|
_metrics.DecGauge(new() { GaugeName = MetricsAPI.GaugeFilesTotal, Value = 1 });
|
||||||
|
file.Delete();
|
||||||
|
_logger.LogInformation("File not in DB, deleting: {fileName}", file.FullName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Grpc.AspNetCore" Version="2.47.0" />
|
<PackageReference Include="Grpc.AspNetCore" Version="2.47.0" />
|
||||||
<PackageReference Include="Grpc.Net.Client" Version="2.47.0" />
|
<PackageReference Include="Grpc.Net.Client" Version="2.47.0" />
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="6.0.8" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Hosting.Systemd" Version="6.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Hosting.Systemd" Version="6.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|||||||
@@ -48,6 +48,8 @@ public class Startup
|
|||||||
options.EnableThreadSafetyChecks(false);
|
options.EnableThreadSafetyChecks(false);
|
||||||
}, mareSettings.GetValue("DbContextPoolSize", 1024));
|
}, mareSettings.GetValue("DbContextPoolSize", 1024));
|
||||||
|
|
||||||
|
services.AddHostedService<CleanupService>();
|
||||||
|
|
||||||
services.AddAuthentication(options =>
|
services.AddAuthentication(options =>
|
||||||
{
|
{
|
||||||
options.DefaultScheme = SecretKeyGrpcAuthenticationHandler.AuthScheme;
|
options.DefaultScheme = SecretKeyGrpcAuthenticationHandler.AuthScheme;
|
||||||
|
|||||||
Reference in New Issue
Block a user