feat/Update_Controllers_to_Allow_for_Premium_Membership
This commit is contained in:
@@ -1,69 +1,60 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using JobTrackerApi.Data;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace JobTrackerApi.Services
|
||||
namespace JobTrackerApi.Services;
|
||||
|
||||
// Applies deterministic auto-ghost transitions only when explicitly enabled.
|
||||
public sealed class RulesHostedService(
|
||||
BackgroundTenantRunner tenants,
|
||||
IConfiguration configuration,
|
||||
ILogger<RulesHostedService> logger,
|
||||
IStartupReadiness startupReadiness) : BackgroundService
|
||||
{
|
||||
// Periodically applies "auto ghost" transitions.
|
||||
public sealed class RulesHostedService : BackgroundService
|
||||
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
||||
{
|
||||
private readonly IServiceProvider _services;
|
||||
private readonly IStartupReadiness _startupReadiness;
|
||||
|
||||
public RulesHostedService(IServiceProvider services, IStartupReadiness startupReadiness)
|
||||
await startupReadiness.WaitUntilReadyAsync(stoppingToken);
|
||||
if (!configuration.GetValue("Workers:RulesEnabled", false))
|
||||
{
|
||||
_services = services;
|
||||
_startupReadiness = startupReadiness;
|
||||
logger.LogInformation("Rules worker disabled (Workers:RulesEnabled=false).");
|
||||
return;
|
||||
}
|
||||
|
||||
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
||||
await Task.Delay(TimeSpan.FromSeconds(2), stoppingToken);
|
||||
while (!stoppingToken.IsCancellationRequested)
|
||||
{
|
||||
await _startupReadiness.WaitUntilReadyAsync(stoppingToken);
|
||||
// Small initial delay to let app start.
|
||||
await Task.Delay(TimeSpan.FromSeconds(2), stoppingToken);
|
||||
|
||||
while (!stoppingToken.IsCancellationRequested)
|
||||
{
|
||||
try
|
||||
{
|
||||
using var scope = _services.CreateScope();
|
||||
var db = scope.ServiceProvider.GetRequiredService<JobTrackerContext>();
|
||||
|
||||
var settings = await RulesEngine.GetSettings(db, stoppingToken);
|
||||
var now = DateTime.Now;
|
||||
|
||||
// Get last correspondence per job (single query).
|
||||
var lastMsg = await db.Correspondences
|
||||
.GroupBy(c => c.JobApplicationId)
|
||||
.Select(g => new { JobApplicationId = g.Key, Last = g.Max(x => x.Date) })
|
||||
.ToDictionaryAsync(x => x.JobApplicationId, x => (DateTime?)x.Last, stoppingToken);
|
||||
|
||||
var jobs = await db.JobApplications
|
||||
.Where(j => !j.IsDeleted && j.Status != "Ghosted")
|
||||
.ToListAsync(stoppingToken);
|
||||
|
||||
var changed = 0;
|
||||
foreach (var j in jobs)
|
||||
{
|
||||
lastMsg.TryGetValue(j.Id, out var lm);
|
||||
var d = RulesEngine.Evaluate(settings, j, now, lm);
|
||||
if (d.ShouldGhost)
|
||||
{
|
||||
j.Status = "Ghosted";
|
||||
changed++;
|
||||
}
|
||||
}
|
||||
|
||||
if (changed > 0)
|
||||
await db.SaveChangesAsync(stoppingToken);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Best-effort background job; swallow errors.
|
||||
}
|
||||
|
||||
await Task.Delay(TimeSpan.FromMinutes(30), stoppingToken);
|
||||
}
|
||||
await RunOnceAsync(stoppingToken);
|
||||
await Task.Delay(TimeSpan.FromMinutes(30), stoppingToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Task<BackgroundWorkerRunResult> RunOnceAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
if (!configuration.GetValue("Workers:RulesEnabled", false))
|
||||
return Task.FromResult(BackgroundWorkerRunResult.Disabled);
|
||||
|
||||
return tenants.RunForJobOwnersAsync("rules", ProcessOwnerAsync, cancellationToken);
|
||||
}
|
||||
|
||||
private static async Task ProcessOwnerAsync(IServiceProvider services, CancellationToken cancellationToken)
|
||||
{
|
||||
var db = services.GetRequiredService<JobTrackerContext>();
|
||||
var settings = await RulesEngine.GetSettings(db, cancellationToken);
|
||||
var now = DateTime.Now;
|
||||
var lastMessages = await db.Correspondences
|
||||
.GroupBy(message => message.JobApplicationId)
|
||||
.Select(group => new { JobApplicationId = group.Key, Last = group.Max(x => x.Date) })
|
||||
.ToDictionaryAsync(x => x.JobApplicationId, x => (DateTime?)x.Last, cancellationToken);
|
||||
var jobs = await db.JobApplications
|
||||
.Where(job => !job.IsDeleted && job.Status != "Ghosted")
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
foreach (var job in jobs)
|
||||
{
|
||||
lastMessages.TryGetValue(job.Id, out var lastMessage);
|
||||
if (RulesEngine.Evaluate(settings, job, now, lastMessage).ShouldGhost)
|
||||
job.Status = "Ghosted";
|
||||
}
|
||||
|
||||
await db.SaveChangesAsync(cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user