6d2ad6f87e
- ListingPolicy.JobFreshnessDays=30: public /Jobs and home hide jobs older than the cutoff (shifts already require Date>=today) - ListingArchiver flips stale Open→Expired: shifts past their date, jobs older than the cutoff. Runs at startup and on every IngestionWorker cycle (independent of ingestion being enabled) - Verified: backdated job dropped off /Jobs (6→5) and was archived to Expired on the sweep Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
58 lines
2.3 KiB
C#
58 lines
2.3 KiB
C#
namespace JobsMedical.Web.Services.Scraping;
|
|
|
|
/// <summary>
|
|
/// Periodically runs the ingestion engine when the admin has turned auto-ingest ON
|
|
/// (AppSetting.AutoIngestEnabled) — read fresh from the DB each cycle, so it can be toggled at
|
|
/// runtime from the admin panel with no redeploy. When off, it idles and re-checks.
|
|
/// </summary>
|
|
public class IngestionWorker : BackgroundService
|
|
{
|
|
private readonly IServiceScopeFactory _scopes;
|
|
private readonly ILogger<IngestionWorker> _log;
|
|
|
|
public IngestionWorker(IServiceScopeFactory scopes, ILogger<IngestionWorker> log)
|
|
{
|
|
_scopes = scopes;
|
|
_log = log;
|
|
}
|
|
|
|
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
|
{
|
|
// Small startup delay so the DB/migrations are ready.
|
|
try { await Task.Delay(TimeSpan.FromSeconds(20), stoppingToken); }
|
|
catch (OperationCanceledException) { return; }
|
|
|
|
while (!stoppingToken.IsCancellationRequested)
|
|
{
|
|
var idleMinutes = 10;
|
|
try
|
|
{
|
|
using var scope = _scopes.CreateScope();
|
|
|
|
// Always archive stale listings (independent of ingestion being on).
|
|
await scope.ServiceProvider.GetRequiredService<ListingArchiver>().ArchiveStaleAsync(stoppingToken);
|
|
|
|
var settings = await scope.ServiceProvider
|
|
.GetRequiredService<SettingsService>().GetAsync();
|
|
|
|
if (settings.AutoIngestEnabled)
|
|
{
|
|
var svc = scope.ServiceProvider.GetRequiredService<IngestionService>();
|
|
var summary = await svc.RunAsync(stoppingToken);
|
|
_log.LogInformation("Auto-ingest: queued={Q} published={P} flagged={F} spam={S} dupes={D}",
|
|
summary.TotalQueued, summary.TotalPublished, summary.TotalFlagged,
|
|
summary.TotalSpam, summary.TotalDuplicates);
|
|
idleMinutes = Math.Max(1, settings.IngestIntervalMinutes);
|
|
}
|
|
}
|
|
catch (Exception ex) when (ex is not OperationCanceledException)
|
|
{
|
|
_log.LogError(ex, "Auto-ingest cycle failed");
|
|
}
|
|
|
|
try { await Task.Delay(TimeSpan.FromMinutes(idleMinutes), stoppingToken); }
|
|
catch (OperationCanceledException) { break; }
|
|
}
|
|
}
|
|
}
|