using System.Reflection; using Cleanuparr.Infrastructure.Services; using Cleanuparr.Persistence; using Cleanuparr.Persistence.Providers; using Microsoft.EntityFrameworkCore; namespace Cleanuparr.Api; public static class HostExtensions { public static IHost Init(this WebApplication app) { ILogger logger = app.Services.GetRequiredService>(); AppStatusSnapshot statusSnapshot = app.Services.GetRequiredService(); Version? version = Assembly.GetExecutingAssembly().GetName().Version; string? formattedVersion = FormatVersion(version); if (statusSnapshot.UpdateCurrentVersion(formattedVersion, out _)) { logger.LogDebug("App status current version set to {Version}", formattedVersion); } logger.LogInformation( version is null ? "Cleanuparr version not detected" : $"Cleanuparr {formattedVersion}" ); logger.LogInformation("timezone: {tz}", TimeZoneInfo.Local.DisplayName); LogGcConfiguration(logger); return app; } private static void LogGcConfiguration(ILogger logger) { // Surface the active GC settings GCMemoryInfo info = GC.GetGCMemoryInfo(); long totalAvailableMb = info.TotalAvailableMemoryBytes / (1024 * 1024); long heapHardLimitMb = info.HighMemoryLoadThresholdBytes / (1024 * 1024); logger.LogInformation( "Garbage Collector config | server={ServerGC} concurrent={ConcurrentGC} latencyMode={Latency} totalAvailable={TotalMb} MB highMemoryLoadThreshold={HighMb} MB", System.Runtime.GCSettings.IsServerGC, info.Concurrent, System.Runtime.GCSettings.LatencyMode, totalAvailableMb, heapHardLimitMb); } private static string? FormatVersion(Version? version) { if (version is null) { return null; } if (version.Build >= 0) { return $"v{version.Major}.{version.Minor}.{version.Build}"; } return $"v{version.Major}.{version.Minor}"; } public static async Task InitAsync(this WebApplicationBuilder builder) { IDatabaseProvider provider = DatabaseProviderFactory.Current; // Apply data db migrations first — events migrations may ATTACH cleanuparr.db // and reference its schema, so it must be up to date before events migrate. await using DataContext configContext = DataContext.CreateStaticInstance(); if ((await configContext.Database.GetPendingMigrationsAsync()).Any()) { await configContext.Database.MigrateAsync(); } await provider.OnPostMigrateAsync(configContext.Database, DbContextKind.Data, CancellationToken.None); await using EventsContext eventsContext = EventsContext.CreateStaticInstance(); if ((await eventsContext.Database.GetPendingMigrationsAsync()).Any()) { await eventsContext.Database.MigrateAsync(); } await provider.OnPostMigrateAsync(eventsContext.Database, DbContextKind.Events, CancellationToken.None); await using UsersContext usersContext = UsersContext.CreateStaticInstance(); if ((await usersContext.Database.GetPendingMigrationsAsync()).Any()) { await usersContext.Database.MigrateAsync(); } await provider.OnPostMigrateAsync(usersContext.Database, DbContextKind.Users, CancellationToken.None); return builder; } }