fixes etc

This commit is contained in:
Stanley Dimant
2022-08-23 13:02:28 +02:00
parent 2510cce711
commit 74209b3952
7 changed files with 52 additions and 97 deletions

View File

@@ -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);

View File

@@ -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)

View File

@@ -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>

View File

@@ -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)

View File

@@ -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);
} }
} }
} }

View File

@@ -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>

View File

@@ -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;