feat(assets): dynamic settings, IFinlyticLogger, live log streaming, and EF migration
This commit is contained in:
@@ -4,12 +4,13 @@ using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using FinlyticAssets.Models;
|
||||
using FinlyticAssets.Util;
|
||||
using FinlyticCore.Dtos.TradeRepublic;
|
||||
using FinlyticCore.Models.Assets;
|
||||
using FinlyticCore.Services;
|
||||
using FinlyticCore.Services.TradeRepublic;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace FinlyticAssets.Services;
|
||||
|
||||
@@ -20,31 +21,31 @@ namespace FinlyticAssets.Services;
|
||||
public class AssetScannerBackgroundService : BackgroundService
|
||||
{
|
||||
private readonly IServiceScopeFactory _serviceScopeFactory;
|
||||
private readonly ILogger<AssetScannerBackgroundService> _logger;
|
||||
private readonly IFinlyticLogger<AssetScannerBackgroundService> _finlyticLogger;
|
||||
|
||||
private AssetsCount? _assetsCount;
|
||||
private AssetsCount? _currAssetsCount;
|
||||
|
||||
public AssetScannerBackgroundService(IServiceScopeFactory serviceScopeFactory, ILogger<AssetScannerBackgroundService> logger)
|
||||
public AssetScannerBackgroundService(IServiceScopeFactory serviceScopeFactory, IFinlyticLogger<AssetScannerBackgroundService> finlyticLogger)
|
||||
{
|
||||
_serviceScopeFactory = serviceScopeFactory;
|
||||
_logger = logger;
|
||||
_finlyticLogger = finlyticLogger;
|
||||
}
|
||||
|
||||
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
||||
{
|
||||
_logger.LogInformation("[{Channel}] AssetScannerBackgroundService has started.", "AssetsChannel");
|
||||
await _finlyticLogger.LogInfoAsync(SettingKeys.AssetsChannel, "[AssetScannerBackgroundService] AssetScannerBackgroundService has started.");
|
||||
|
||||
try
|
||||
{
|
||||
using var scope = _serviceScopeFactory.CreateScope();
|
||||
var indexService = scope.ServiceProvider.GetRequiredService<IAssetsIndexService>();
|
||||
_logger.LogInformation("[{Channel}] Building initial asset index on service startup...", "AssetsChannel");
|
||||
await _finlyticLogger.LogInfoAsync(SettingKeys.AssetsChannel, "[AssetScannerBackgroundService] Building initial asset index on service startup...");
|
||||
await indexService.ReCreateIndexFileAsync(stoppingToken);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "[{Channel}] Failed to build initial asset index on startup. Continuing service execution.", "AssetsChannel");
|
||||
await _finlyticLogger.LogErrorAsync(SettingKeys.AssetsChannel, ex, "[AssetScannerBackgroundService] Failed to build initial asset index on startup. Continuing service execution.");
|
||||
}
|
||||
|
||||
do
|
||||
@@ -57,7 +58,7 @@ public class AssetScannerBackgroundService : BackgroundService
|
||||
var assetsDbService = scope.ServiceProvider.GetRequiredService<IAssetsDbService>();
|
||||
var indexService = scope.ServiceProvider.GetRequiredService<IAssetsIndexService>();
|
||||
|
||||
_logger.LogInformation("[{Channel}] Requesting total asset counts from Trade Republic...", "AssetsChannel");
|
||||
await _finlyticLogger.LogInfoAsync(SettingKeys.AssetsChannel, "[AssetScannerBackgroundService] Requesting total asset counts from Trade Republic...");
|
||||
_assetsCount = await tradeRepublicService.GetAssetsCount(stoppingToken);
|
||||
_currAssetsCount = new AssetsCount();
|
||||
|
||||
@@ -72,7 +73,7 @@ public class AssetScannerBackgroundService : BackgroundService
|
||||
{
|
||||
if (type != initSettings.CurrentScanningType)
|
||||
{
|
||||
_logger.LogInformation("[{Channel}] Recovery: {AssetType} was already processed. Skipping.", "AssetsChannel", type);
|
||||
await _finlyticLogger.LogInfoAsync(SettingKeys.AssetsChannel, "[AssetScannerBackgroundService] Recovery: {AssetType} was already processed. Skipping.", type);
|
||||
continue;
|
||||
}
|
||||
isRecoveryMode = false;
|
||||
@@ -85,7 +86,7 @@ public class AssetScannerBackgroundService : BackgroundService
|
||||
await settingsService.SaveSettings(settings);
|
||||
}
|
||||
|
||||
_logger.LogInformation("[{Channel}] Processing asset type: {AssetType}...", "AssetsChannel", type);
|
||||
await _finlyticLogger.LogInfoAsync(SettingKeys.AssetsChannel, "[AssetScannerBackgroundService] Processing asset type: {AssetType}...", type);
|
||||
await HandleAssetType(type, tradeRepublicService, settingsService, assetsDbService, indexService, stoppingToken);
|
||||
|
||||
var currentSettings = await settingsService.GetSettings();
|
||||
@@ -96,7 +97,7 @@ public class AssetScannerBackgroundService : BackgroundService
|
||||
if (delaySeconds > 0)
|
||||
{
|
||||
var jitter = Random.Shared.Next(0, Math.Min(15, delaySeconds));
|
||||
_logger.LogInformation("[{Channel}] Waiting {Delay}s before next asset type ({Type}).", "AssetsChannel", delaySeconds + jitter, type);
|
||||
await _finlyticLogger.LogInfoAsync(SettingKeys.AssetsChannel, "[AssetScannerBackgroundService] Waiting {Delay}s before next asset type ({Type}).", delaySeconds + jitter, type);
|
||||
await Task.Delay(TimeSpan.FromSeconds(delaySeconds + jitter), stoppingToken);
|
||||
}
|
||||
}
|
||||
@@ -106,23 +107,23 @@ public class AssetScannerBackgroundService : BackgroundService
|
||||
|
||||
if (!finalSettings.FinishedInitialScan && !stoppingToken.IsCancellationRequested)
|
||||
{
|
||||
_logger.LogInformation("[{Channel}] Initial scan successfully completed. Switching FinishedInitialScan to true.", "AssetsChannel");
|
||||
await _finlyticLogger.LogInfoAsync(SettingKeys.AssetsChannel, "[AssetScannerBackgroundService] Initial scan successfully completed. Switching FinishedInitialScan to true.");
|
||||
finalSettings.FinishedInitialScan = true;
|
||||
}
|
||||
|
||||
await settingsService.SaveSettings(finalSettings);
|
||||
|
||||
_logger.LogInformation("[{Channel}] Full scan cycle completed. Waiting 1 minute before starting the next cycle.", "AssetsChannel");
|
||||
await _finlyticLogger.LogInfoAsync(SettingKeys.AssetsChannel, "[AssetScannerBackgroundService] Full scan cycle completed. Waiting 1 minute before starting the next cycle.");
|
||||
await Task.Delay(TimeSpan.FromMinutes(1), stoppingToken);
|
||||
}
|
||||
catch (Exception e) when (!stoppingToken.IsCancellationRequested)
|
||||
{
|
||||
_logger.LogError(e, "[{Channel}] An unhandled exception occurred in AssetScannerBackgroundService. Retrying in 10 seconds.", "AssetsChannel");
|
||||
await _finlyticLogger.LogErrorAsync(SettingKeys.AssetsChannel, e, "[AssetScannerBackgroundService] An unhandled exception occurred in AssetScannerBackgroundService. Retrying in 10 seconds.");
|
||||
try { await Task.Delay(TimeSpan.FromSeconds(10), stoppingToken); } catch { /* Ignore */ }
|
||||
}
|
||||
} while (!stoppingToken.IsCancellationRequested);
|
||||
|
||||
_logger.LogInformation("[{Channel}] AssetScannerBackgroundService is stopping.", "AssetsChannel");
|
||||
await _finlyticLogger.LogInfoAsync(SettingKeys.AssetsChannel, "[AssetScannerBackgroundService] AssetScannerBackgroundService is stopping.");
|
||||
}
|
||||
|
||||
private async Task HandleAssetType(
|
||||
@@ -136,7 +137,7 @@ public class AssetScannerBackgroundService : BackgroundService
|
||||
var totalCount = _assetsCount?.GetCountFromType(type) ?? 0;
|
||||
if (totalCount == 0)
|
||||
{
|
||||
_logger.LogWarning("[{Channel}] No assets found for type {AssetType}.", "AssetsChannel", type);
|
||||
await _finlyticLogger.LogWarningAsync(SettingKeys.AssetsChannel, "[AssetScannerBackgroundService] No assets found for type {AssetType}.", type);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -149,8 +150,8 @@ public class AssetScannerBackgroundService : BackgroundService
|
||||
if (settings.CurrentScanningType == type && settings.CurrentScanningPage > 0)
|
||||
{
|
||||
currentItemOffset = (settings.CurrentScanningPage - 1) * pageSize;
|
||||
_logger.LogInformation("[{Channel}] Resuming full scan for {AssetType} from Page {Page} (Calculated Offset: {Offset}).",
|
||||
"AssetsChannel", type, settings.CurrentScanningPage, currentItemOffset);
|
||||
await _finlyticLogger.LogInfoAsync(SettingKeys.AssetsChannel, "[AssetScannerBackgroundService] Resuming full scan for {AssetType} from Page {Page} (Calculated Offset: {Offset}).",
|
||||
type, settings.CurrentScanningPage, currentItemOffset);
|
||||
}
|
||||
|
||||
while (currentItemOffset < totalCount && !stoppingToken.IsCancellationRequested)
|
||||
@@ -164,15 +165,14 @@ public class AssetScannerBackgroundService : BackgroundService
|
||||
currentSettings.CurrentScanningPage = currentPage;
|
||||
await settingsDbService.SaveSettings(currentSettings);
|
||||
|
||||
_logger.LogDebug("Fetching {AssetType} - Page {Page}. Numerical Offset: {Offset}/{Total}",
|
||||
await _finlyticLogger.LogDebugAsync(SettingKeys.AssetsChannel, "[AssetScannerBackgroundService] Fetching {AssetType} - Page {Page}. Numerical Offset: {Offset}/{Total}",
|
||||
type, currentPage, currentItemOffset, totalCount);
|
||||
|
||||
var assets = await tradeRepublicService.GetAssets(type, currentPage, pageSize, stoppingToken);
|
||||
|
||||
// Keine Ergebnisse geliefert -> Katalogende erreicht
|
||||
if (assets?.Results == null || assets.Results.Count == 0)
|
||||
{
|
||||
_logger.LogInformation("[{Channel}] Fetch for {AssetType} (Page {Page}) returned no results. Reached end of available assets.", "AssetsChannel", type, currentPage);
|
||||
await _finlyticLogger.LogInfoAsync(SettingKeys.AssetsChannel, "[AssetScannerBackgroundService] Fetch for {AssetType} (Page {Page}) returned no results. Reached end of available assets.", type, currentPage);
|
||||
currentSettings.CurrentScanningPage = 0;
|
||||
await settingsDbService.SaveSettings(currentSettings);
|
||||
break;
|
||||
@@ -183,10 +183,9 @@ public class AssetScannerBackgroundService : BackgroundService
|
||||
|
||||
currentItemOffset += assets.Results.Count;
|
||||
|
||||
// Unvollständige Seite -> Letzte Seite abgearbeitet
|
||||
if (assets.Results.Count < pageSize)
|
||||
{
|
||||
_logger.LogInformation("[{Channel}] Reached the last page for {AssetType}.", "AssetsChannel", type);
|
||||
await _finlyticLogger.LogInfoAsync(SettingKeys.AssetsChannel, "[AssetScannerBackgroundService] Reached the last page for {AssetType}.", type);
|
||||
currentSettings.CurrentScanningPage = 0;
|
||||
await settingsDbService.SaveSettings(currentSettings);
|
||||
break;
|
||||
@@ -198,16 +197,15 @@ public class AssetScannerBackgroundService : BackgroundService
|
||||
|
||||
if (delaySeconds > 0)
|
||||
{
|
||||
// Angemessener Jitter (0 bis max. 5 Sek. bzw. kleiner als delaySeconds)
|
||||
var maxJitter = Math.Min(5, delaySeconds);
|
||||
var jitter = Random.Shared.Next(0, maxJitter + 1);
|
||||
_logger.LogDebug("Waiting {Delay} seconds before the next batch.", delaySeconds + jitter);
|
||||
await _finlyticLogger.LogDebugAsync(SettingKeys.AssetsChannel, "[AssetScannerBackgroundService] Waiting {Delay} seconds before the next batch.", delaySeconds + jitter);
|
||||
await Task.Delay(TimeSpan.FromSeconds(delaySeconds + jitter), stoppingToken);
|
||||
}
|
||||
}
|
||||
|
||||
_logger.LogInformation("[{Channel}] Finished scanning {AssetType}. Total scanned in this cycle: {Count}/{Total}",
|
||||
"AssetsChannel", type, _currAssetsCount.GetCountFromType(type), totalCount);
|
||||
await _finlyticLogger.LogInfoAsync(SettingKeys.AssetsChannel, "[AssetScannerBackgroundService] Finished scanning {AssetType}. Total scanned in this cycle: {Count}/{Total}",
|
||||
type, _currAssetsCount.GetCountFromType(type), totalCount);
|
||||
}
|
||||
|
||||
private async Task ProcessAssets(
|
||||
@@ -219,11 +217,11 @@ public class AssetScannerBackgroundService : BackgroundService
|
||||
if (assets == null || assets.Count == 0) return;
|
||||
|
||||
var changedRows = await assetsDbService.AddOrUpdateAssetsAsync(assets);
|
||||
_logger.LogInformation("[{Channel}] [Scan] {Count} assets passed to the DB service. {Changed} modifications/inserts executed.", "AssetsChannel", assets.Count, changedRows);
|
||||
await _finlyticLogger.LogInfoAsync(SettingKeys.AssetsChannel, "[AssetScannerBackgroundService] [Scan] {Count} assets passed to the DB service. {Changed} modifications/inserts executed.", assets.Count, changedRows);
|
||||
|
||||
if (changedRows > 0)
|
||||
{
|
||||
_logger.LogInformation("[{Channel}] Database modifications detected. Recreating the asset index file...", "AssetsChannel");
|
||||
await _finlyticLogger.LogInfoAsync(SettingKeys.AssetsChannel, "[AssetScannerBackgroundService] Database modifications detected. Recreating the asset index file...");
|
||||
await indexService.ReCreateIndexFileAsync(stoppingToken);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user