fix(news): use CreateAsyncScope for Playwright service and gracefully handle DbUpdateException on duplicate URLs
This commit is contained in:
@@ -158,10 +158,23 @@ public class NewsDbService : INewsDbService
|
|||||||
await _context.SaveChangesAsync();
|
await _context.SaveChangesAsync();
|
||||||
await _finlyticLogger.LogDebugAsync(SettingKeys.NewsChannel, "[Lifecycle] Registered new article with status 'Pending'. ID: {Id}, Url: {Url}", article.Id, trimmedUrl);
|
await _finlyticLogger.LogDebugAsync(SettingKeys.NewsChannel, "[Lifecycle] Registered new article with status 'Pending'. ID: {Id}, Url: {Url}", article.Id, trimmedUrl);
|
||||||
}
|
}
|
||||||
catch (DbUpdateConcurrencyException)
|
catch (DbUpdateException ex)
|
||||||
{
|
{
|
||||||
await _finlyticLogger.LogWarningAsync(SettingKeys.NewsChannel, "[NewsChannel] Concurrency hit during insert for URL: {Url}. Fetching existing fallback.", trimmedUrl);
|
_context.Entry(article).State = EntityState.Detached;
|
||||||
return await _context.NewsArticles.FirstAsync(a => a.SourceUrl == trimmedUrl);
|
if (article.MatchedAssets != null)
|
||||||
|
{
|
||||||
|
foreach (var match in article.MatchedAssets)
|
||||||
|
{
|
||||||
|
_context.Entry(match).State = EntityState.Detached;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await _finlyticLogger.LogWarningAsync(SettingKeys.NewsChannel, "[NewsChannel] Unique constraint or concurrency hit during insert for URL: {Url}. Fetching existing fallback. ({Message})", trimmedUrl, ex.InnerException?.Message ?? ex.Message);
|
||||||
|
var existing = await _context.NewsArticles.AsNoTracking().FirstOrDefaultAsync(a => a.SourceUrl == trimmedUrl);
|
||||||
|
if (existing != null)
|
||||||
|
{
|
||||||
|
return existing;
|
||||||
|
}
|
||||||
|
throw;
|
||||||
}
|
}
|
||||||
|
|
||||||
return article;
|
return article;
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ public class NewsScraperBackgroundService : BackgroundService
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
using var scope = _scopeFactory.CreateScope();
|
await using var scope = _scopeFactory.CreateAsyncScope();
|
||||||
var settings = scope.ServiceProvider.GetRequiredService<ISettingsService>();
|
var settings = scope.ServiceProvider.GetRequiredService<ISettingsService>();
|
||||||
bool enabled = await settings.GetSettingAsync(SettingKeys.EnableAutoScraping, stoppingToken);
|
bool enabled = await settings.GetSettingAsync(SettingKeys.EnableAutoScraping, stoppingToken);
|
||||||
|
|
||||||
@@ -82,7 +82,7 @@ public class NewsScraperBackgroundService : BackgroundService
|
|||||||
int intervalMinutes = 15;
|
int intervalMinutes = 15;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
using var scope = _scopeFactory.CreateScope();
|
await using var scope = _scopeFactory.CreateAsyncScope();
|
||||||
var settings = scope.ServiceProvider.GetRequiredService<ISettingsService>();
|
var settings = scope.ServiceProvider.GetRequiredService<ISettingsService>();
|
||||||
intervalMinutes = await settings.GetSettingAsync(SettingKeys.ScrapeIntervalMinutes, stoppingToken);
|
intervalMinutes = await settings.GetSettingAsync(SettingKeys.ScrapeIntervalMinutes, stoppingToken);
|
||||||
}
|
}
|
||||||
@@ -107,7 +107,7 @@ public class NewsScraperBackgroundService : BackgroundService
|
|||||||
|
|
||||||
private async Task RunScrapingCycleAsync(CancellationToken stoppingToken)
|
private async Task RunScrapingCycleAsync(CancellationToken stoppingToken)
|
||||||
{
|
{
|
||||||
using var scope = _scopeFactory.CreateScope();
|
await using var scope = _scopeFactory.CreateAsyncScope();
|
||||||
var dbService = scope.ServiceProvider.GetRequiredService<INewsDbService>();
|
var dbService = scope.ServiceProvider.GetRequiredService<INewsDbService>();
|
||||||
var discoveryService = scope.ServiceProvider.GetRequiredService<IArticleDiscoveryService>();
|
var discoveryService = scope.ServiceProvider.GetRequiredService<IArticleDiscoveryService>();
|
||||||
var scraperService = scope.ServiceProvider.GetRequiredService<IPlaywrightScraperService>();
|
var scraperService = scope.ServiceProvider.GetRequiredService<IPlaywrightScraperService>();
|
||||||
|
|||||||
Reference in New Issue
Block a user