feat(backend): add admin evaluation history, engine, simulation, bot API controllers and global exception middleware

This commit is contained in:
2026-08-24 21:37:32 +02:00
parent 6974b2075b
commit 676496b77d
37 changed files with 88203 additions and 83075 deletions
@@ -33,7 +33,7 @@ public class FavoritesPriceBackgroundService(
logger.LogWarning(ex, "[FavoritesPriceBackgroundService] Error broadcasting price updates.");
}
await Task.Delay(10000, stoppingToken);
await Task.Delay(2000, stoppingToken);
}
}
@@ -50,24 +50,23 @@ public class FavoritesPriceBackgroundService(
if (userFavorites.Count == 0) return;
// 2. Pro User einfach die Kurse abfragen und senden
// 2. Pro User einfach die Kurse parallel abfragen und senden
foreach (var userGroup in userFavorites.GroupBy(f => f.UserId.ToString()))
{
var userId = userGroup.Key;
var priceUpdates = new Dictionary<string, object>();
var priceUpdates = new System.Collections.Concurrent.ConcurrentDictionary<string, object>();
foreach (var fav in userGroup)
var tasks = userGroup.Select(async fav =>
{
var cleanIsin = fav.Isin.Trim().ToUpperInvariant();
if (!mqttClient.IsConnected) continue;
if (!mqttClient.IsConnected) return;
try
{
var livePrice = await mqttClient.SendRpcRequestAsync<LivePriceDto, IsinRequest>(
"tr_GetLivePrice",
new IsinRequest(cleanIsin),
TimeSpan.FromSeconds(2)
TimeSpan.FromSeconds(4)
);
if (livePrice != null)
@@ -80,12 +79,14 @@ public class FavoritesPriceBackgroundService(
}
}
catch { /* Ignorieren bei Einzel-Timeout */ }
}
});
if (priceUpdates.Count > 0)
await Task.WhenAll(tasks);
if (!priceUpdates.IsEmpty)
{
await hubContext.Clients.Group(FavoritesPriceHub.GetGroupName(userId))
.SendAsync("ReceiveFavoritePrices", priceUpdates, cancellationToken);
.SendAsync("ReceiveFavoritePrices", new Dictionary<string, object>(priceUpdates), cancellationToken);
}
}
}