76 lines
2.6 KiB
C#
76 lines
2.6 KiB
C#
using Microsoft.EntityFrameworkCore;
|
|
|
|
public class SepsisBundleMonitorService : BackgroundService
|
|
{
|
|
private static readonly TimeSpan ScanInterval = TimeSpan.FromMinutes(5);
|
|
|
|
private readonly IServiceProvider _services;
|
|
private readonly ClinicalMetrics _metrics;
|
|
private readonly ILogger<SepsisBundleMonitorService> _logger;
|
|
|
|
public SepsisBundleMonitorService(
|
|
IServiceProvider services,
|
|
ClinicalMetrics metrics,
|
|
ILogger<SepsisBundleMonitorService> logger)
|
|
{
|
|
_services = services;
|
|
_metrics = metrics;
|
|
_logger = logger;
|
|
}
|
|
|
|
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
|
{
|
|
_logger.LogInformation("Sepsis bundle monitor started. ScanInterval={Interval}", ScanInterval);
|
|
|
|
while (!stoppingToken.IsCancellationRequested)
|
|
{
|
|
try
|
|
{
|
|
await ScanOverdueBundlesAsync(stoppingToken);
|
|
}
|
|
catch (Exception ex) when (ex is not OperationCanceledException)
|
|
{
|
|
_logger.LogError(ex, "Sepsis bundle monitor error — will retry on next scan cycle");
|
|
}
|
|
|
|
await Task.Delay(ScanInterval, stoppingToken);
|
|
}
|
|
}
|
|
|
|
internal async Task ScanOverdueBundlesAsync(CancellationToken ct)
|
|
{
|
|
using var scope = _services.CreateScope();
|
|
var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
|
|
|
var overdue = await db.SepsisBundles
|
|
.Where(b => b.ComplianceStatus == SepsisBundleComplianceStatus.InProgress
|
|
&& b.DeadlineAt < DateTimeOffset.UtcNow)
|
|
.ToListAsync(ct);
|
|
|
|
if (overdue.Count == 0)
|
|
return;
|
|
|
|
foreach (var bundle in overdue)
|
|
{
|
|
bundle.ComplianceStatus = SepsisBundleComplianceStatus.NonCompliant;
|
|
|
|
_metrics.SepsisBundleComplianceTotal
|
|
.WithLabels("NON_COMPLIANT").Inc();
|
|
|
|
var incompleteCount = await db.SepsisBundleElements
|
|
.CountAsync(e => e.BundleId == bundle.Id
|
|
&& e.Status != SepsisBundleElementStatus.Completed, ct);
|
|
|
|
_logger.LogWarning(
|
|
"Sepsis bundle {BundleId} for encounter {EncounterId} marked NON_COMPLIANT — " +
|
|
"deadline {Deadline} passed with {Incomplete} incomplete elements",
|
|
bundle.Id, bundle.EncounterId, bundle.DeadlineAt, incompleteCount);
|
|
}
|
|
|
|
await db.SaveChangesAsync(ct);
|
|
|
|
_logger.LogInformation(
|
|
"Sepsis bundle monitor marked {Count} overdue bundles as NON_COMPLIANT", overdue.Count);
|
|
}
|
|
}
|