SoftTraderBackend/ServiceHandler/NewsSentimentRefreshService.cs
2026-03-20 10:42:48 -04:00

79 lines
2.0 KiB
C#

using Backend.Interface;
namespace Backend.ServiceHander
{
public sealed class NewsSentimentRefreshService : BackgroundService
{
private static readonly TimeSpan PollInterval = TimeSpan.FromMinutes(15);
private static readonly TimeZoneInfo Pacific = TimeZoneInfo.FindSystemTimeZoneById("America/Los_Angeles");
private readonly IServiceProvider _services;
private readonly ILogger<NewsSentimentRefreshService> _logger;
public NewsSentimentRefreshService(
IServiceProvider services,
ILogger<NewsSentimentRefreshService> logger)
{
_services = services;
_logger = logger;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
if (IsWithinActiveWindow())
{
await RefreshAsync(stoppingToken);
}
else
{
_logger.LogDebug("Outside active window (weekdays 07:00-20:00 PST), skipping refresh.");
}
await Task.Delay(PollInterval, stoppingToken);
}
}
private static bool IsWithinActiveWindow()
{
var pacificNow = TimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow, Pacific);
if (pacificNow.DayOfWeek is DayOfWeek.Saturday or DayOfWeek.Sunday)
return false;
var hour = pacificNow.Hour;
return hour >= 7 && hour < 20;
}
private async Task RefreshAsync(CancellationToken cancellationToken)
{
try
{
var interests = _services.GetRequiredService<IUserInterestStore>();
var sentiment = _services.GetRequiredService<NewsSentimentService>();
var keywords = await interests.FetchAllDistinctValuesAsync(cancellationToken);
_logger.LogInformation("Refreshing news for {Count} keywords.", keywords.Count);
foreach (var keyword in keywords)
{
try
{
await sentiment.AnalyzeAsync(keyword, cancellationToken);
}
catch (Exception ex)
{
_logger.LogWarning(ex, "Failed to refresh news for keyword '{Keyword}'.", keyword);
}
}
}
catch (Exception ex)
{
_logger.LogError(ex, "News sentiment refresh cycle failed.");
}
}
}
}