Files
adas-core/adas-core.Application/Services/SchedulerService.cs
T

1006 lines
41 KiB
C#

using System.Reflection;
using System.Text;
using adas_core.Application.Providers;
using adas_core.Application.Services.Interfaces;
using adas_core.Domain.Models;
using adas_core.Domain.Models.AppSettings;
using adas_core.Domain.Models.Providers;
using adas_core.Domain.Utils;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Quartz;
using Quartz.Impl;
using Serilog;
using ILogger = Serilog.ILogger;
using Options = Microsoft.Extensions.Options.Options;
namespace adas_core.Application.Services;
public class SchedulerService
{
private readonly bool _activateCheckExpiredAlerts;
private readonly bool _activateCheckExpiredObservations;
private readonly bool _activateCheckInactivePatients;
private readonly bool _activateSchedulerCheckActiveTreatmentsJob;
private readonly bool _activateSchedulerCheckActiveAppointmentsJob;
private readonly bool _activateSchedulerCheckHydricBalance;
private readonly bool _activateSchedulerCheckNewsJob;
private readonly bool _activateSchedulerCheckOpiateBoluses;
private readonly bool _activateSchedulerGetProvidersObservations;
private readonly ArchiveNurseData _archiveNurseData;
private readonly int _archivePatientsWithoutObservationsSinceHours;
private readonly Lazy<ICalculatedObservationsService> _calculatedObservationsService;
private readonly int _checkActiveTreatmentsSchedulerIntervalMinutes;
private readonly int _checkActiveAppointmentsSchedulerIntervalMinutes;
private readonly int _checkExpiredAlertsIntervalSeconds;
private readonly int _checkExpiredObservationsIntervalMinutes;
private readonly int _checkInactivePatientSchedulerIntervalHours;
private readonly int _checkNewsJobIntervalMinutes;
private readonly Lazy<IConfigObservationService> _configObservationService;
private readonly int _getProviderObservationsIntervalMinutes;
private readonly IHttpClientFactory _httpClientFactory;
private readonly ILogger<SchedulerService> _logger;
private readonly Lazy<IMedicineService> _medicineService;
private readonly Lazy<IObservationService> _observationService;
private readonly Lazy<IPatientCarePlanService> _patientProcedureService;
private readonly Lazy<IPatientService> _patientService;
private readonly IOptions<List<ProvidersSettings>> _providersSettings;
private readonly int _sinceDischargeTimeToArchive;
private readonly Lazy<ITreatmentService> _treatmentService;
private readonly Lazy<IAppointmentService> _appointmentService;
private readonly Lazy<IDiagnosisService> _diagnosisService;
public SchedulerService(IOptions<ApiSettings> apiSettings,
IOptions<List<ProvidersSettings>> providersSettings,
Lazy<IPatientService> patientService,
Lazy<ITreatmentService> treatmentService,
Lazy<IAppointmentService> appointmentService,
Lazy<IDiagnosisService> diagnosisService,
Lazy<IMedicineService> medicineService,
Lazy<IObservationService> observationService,
Lazy<IConfigObservationService> configObservationService,
ILogger<SchedulerService> logger,
IHttpClientFactory httpClientFactory,
Lazy<ICalculatedObservationsService> calculatedObservationsService,
Lazy<IPatientCarePlanService> patientProcedureService)
{
_patientService = patientService;
_treatmentService = treatmentService;
_appointmentService = appointmentService;
_diagnosisService = diagnosisService;
_medicineService = medicineService;
_observationService = observationService;
_configObservationService = configObservationService;
_providersSettings = providersSettings;
_httpClientFactory = httpClientFactory;
_calculatedObservationsService = calculatedObservationsService;
_patientProcedureService = patientProcedureService;
_logger = logger;
//LogExecutionContext.TrySetTraceIdentifier(Guid.NewGuid().ToString(), true);
_archivePatientsWithoutObservationsSinceHours =
apiSettings.Value.ArchivePatientsWithoutObservationsSinceHours ?? 24;
var checkInactivePatientSchedulerIntervalHours =
apiSettings.Value.CheckInactivePatientSchedulerIntervalHours;
_checkInactivePatientSchedulerIntervalHours = checkInactivePatientSchedulerIntervalHours ?? 12;
var checkActiveTreatmentsSchedulerIntervalMinutes =
apiSettings.Value.CheckActiveTreatmentsSchedulerIntervalMinutes;
_checkActiveTreatmentsSchedulerIntervalMinutes = checkActiveTreatmentsSchedulerIntervalMinutes ?? 5;
var checkActiveAppointmentsSchedulerIntervalMinutes =
apiSettings.Value.CheckActiveAppointmentsSchedulerIntervalMinutes;
_checkActiveAppointmentsSchedulerIntervalMinutes = checkActiveAppointmentsSchedulerIntervalMinutes ?? 60;
var getProvidersObservationsIntervalMinutes =
apiSettings.Value.GetProvidersObservationsSchedulerIntervalMinutes;
_getProviderObservationsIntervalMinutes = getProvidersObservationsIntervalMinutes ?? 5;
var sinceDischargeTimeToArchive = apiSettings.Value.SinceDischargeTimeToArchive;
_sinceDischargeTimeToArchive = sinceDischargeTimeToArchive ?? 48;
var activateSchedulerCheckExpiredObservations = apiSettings.Value.ActivateSchedulerCheckExpiredObservation;
_activateCheckExpiredObservations = activateSchedulerCheckExpiredObservations;
_activateCheckExpiredAlerts = apiSettings.Value.ActivateCheckExpiredAlerts;
_activateCheckInactivePatients = apiSettings.Value.ActivateCheckInactivePatients;
_activateSchedulerCheckActiveTreatmentsJob = apiSettings.Value.ActivateSchedulerCheckActiveTreatmentsJob;
_activateSchedulerCheckActiveAppointmentsJob = apiSettings.Value.ActivateSchedulerCheckActiveAppointmentsJob;
_activateSchedulerCheckOpiateBoluses = apiSettings.Value.ActivateSchedulerCheckOpiateBoluses;
_activateSchedulerCheckHydricBalance = apiSettings.Value.ActivateSchedulerCheckHydricBalance;
_activateSchedulerGetProvidersObservations = apiSettings.Value.ActivateSchedulerGetProvidersObservations;
_archiveNurseData = apiSettings.Value.ArchiveNurseData;
var schedulerCheckExpiredObservationsIntervalMinutes =
apiSettings.Value.SchedulerCheckExpiredObservationsIntervalMinutes;
_checkExpiredObservationsIntervalMinutes = schedulerCheckExpiredObservationsIntervalMinutes ?? 3;
var schedulerCheckExpiredAlertsIntervalSeconds =
apiSettings.Value.SchedulerCheckExpiredAlertsIntervalSeconds;
_checkExpiredAlertsIntervalSeconds = schedulerCheckExpiredAlertsIntervalSeconds ?? 6;
_activateSchedulerCheckNewsJob = apiSettings.Value.ActivateSchedulerCheckNewsJob;
_checkNewsJobIntervalMinutes =
apiSettings.Value.CheckNewsJobIntervalMinutes;
Task.Run(InitScheduler);
}
private async Task InitScheduler()
{
//TODO con el cambio a .net core y el repaso a la inyección de dependencias de estructure map
//probar a inyectar la dependencia así https://dev.to/bohdanstupak1/dependency-injection-for-quartz-net-in-net-core-3oh7
CheckInactivePatientsJob.PatientService = _patientService.Value;
CheckActiveTreatmentsJob.MedicineService = _medicineService.Value;
CheckActiveTreatmentsJob.PatientService = _patientService.Value;
CheckActiveTreatmentsJob.TreatmentService = _treatmentService.Value;
CheckActiveTreatmentsJob.CalculatedObservationsService = _calculatedObservationsService.Value;
CheckActiveAppointmentsJob.AppointmentService = _appointmentService.Value;
CheckActiveAppointmentsJob.DiagnosisService = _diagnosisService.Value;
CheckActiveAppointmentsJob.PatientService = _patientService.Value;
ArchiveNurseDataJob.PatientCarePlanService = _patientProcedureService.Value;
ArchiveNurseDataJob.PatientService = _patientService.Value;
ArchiveNurseDataJob.ArchiveNurseDataSettings = _archiveNurseData;
CheckOpiateBolusesJob.PatientService = _patientService.Value;
CheckOpiateBolusesJob.CalculatedObservationsService = _calculatedObservationsService.Value;
CheckHydricBalanceRyCJob.ObservationService = _observationService.Value;
CheckHydricBalanceRyCJob.PatientService = _patientService.Value;
CheckHydricBalanceRyCJob.CalculatedObservationsService = _calculatedObservationsService.Value;
CheckExpiredObservationsJob.ObservationService = _observationService.Value;
CheckExpiredAlertsJob.ObservationService = _observationService.Value;
GetProvidersObservationsJob.ObservationService = _observationService.Value;
GetProvidersObservationsJob.PatientService = _patientService.Value;
GetProvidersObservationsJob.Providers = _providersSettings.Value;
GetProvidersObservationsJob.HttpClientFactory = _httpClientFactory;
CalculateNewsJob.ObservationService = _observationService.Value;
CalculateNewsJob.ConfigObservationService = _configObservationService.Value;
CalculateNewsJob.PatientService = _patientService.Value;
CalculateNewsJob.ExpiresIn = _checkNewsJobIntervalMinutes;
var jobDataMap = new JobDataMap
{
{ "archivePatientsWithoutObservationsSinceHours", _archivePatientsWithoutObservationsSinceHours },
{ "sinceDischargeTime", _sinceDischargeTimeToArchive }
};
// Grab the Scheduler instance from the Factory
var factory = new StdSchedulerFactory();
var scheduler = await factory.GetScheduler();
// and start it off
await scheduler.Start();
var checkInactivePatientsJob = JobBuilder.Create<CheckInactivePatientsJob>()
.UsingJobData(jobDataMap)
.Build();
// Trigger the job to run now, and then repeat every 10 seconds
var checkInactivePatientsTrigger = TriggerBuilder.Create()
.StartNow()
.WithSimpleSchedule(x => x
.WithIntervalInHours(_checkInactivePatientSchedulerIntervalHours)
.RepeatForever())
.Build();
var treatmentsJob = JobBuilder.Create<CheckActiveTreatmentsJob>()
.Build();
// Trigger the job to run now, and then repeat every 10 seconds
var treatmentsTrigger = TriggerBuilder.Create()
.StartNow()
.WithSimpleSchedule(x => x
.WithIntervalInMinutes(_checkActiveTreatmentsSchedulerIntervalMinutes)
.RepeatForever())
.Build();
var appointmentsJob = JobBuilder.Create<CheckActiveAppointmentsJob>()
.Build();
var appointmentsTrigger = TriggerBuilder.Create()
.StartNow()
.WithSimpleSchedule(x => x
.WithIntervalInMinutes(_checkActiveAppointmentsSchedulerIntervalMinutes)
.RepeatForever())
.Build();
//Job only for RYC hydric balance.
//Check every hour if hydric balance of that hour exists and recalculate.
var hydricBalanceJob = JobBuilder.Create<CheckHydricBalanceRyCJob>()
.UsingJobData(jobDataMap)
.Build();
var datetimePlusOneHour = DateTime.UtcNow.AddHours(1);
var hydricBalanceTrigger = TriggerBuilder.Create()
.StartAt(new DateTime(datetimePlusOneHour.Year, datetimePlusOneHour.Month, datetimePlusOneHour.Day,
datetimePlusOneHour.Hour, 0, 0))
.WithSimpleSchedule(x => x
.WithIntervalInHours(1)
.RepeatForever())
.Build();
//Check_error_queues
var opiateBolusesJob = JobBuilder.Create<CheckOpiateBolusesJob>()
.Build();
var opiateBolusesTrigger = TriggerBuilder.Create()
.StartNow()
.WithSimpleSchedule(x => x
.WithIntervalInMinutes(5)
.RepeatForever())
.Build();
//Job to expire expired observations
//Check every minute if observations are expired and recalculate.
var checkExpiredObservationsJob = JobBuilder.Create<CheckExpiredObservationsJob>()
.Build();
var checkExpiredObservationsTrigger = TriggerBuilder.Create()
.StartNow()
.WithSimpleSchedule(x => x
.WithIntervalInMinutes(_checkExpiredObservationsIntervalMinutes)
.RepeatForever())
.Build();
//Job to expire Alert
//Check every minute if Alerts are expired and power off.
var checkExpiredAlertsJob = JobBuilder.Create<CheckExpiredAlertsJob>()
.Build();
var checkExpiredAlertsTrigger = TriggerBuilder.Create()
.StartAt(DateBuilder.FutureDate(30, IntervalUnit.Second)) // Comienza 30segundos después del inicio
.WithSimpleSchedule(x => x
//.WithIntervalInMinutes(_checkExpiredAlertsIntervalMinutes)
.WithIntervalInSeconds(_checkExpiredAlertsIntervalSeconds)
.RepeatForever())
.Build();
//Job to get Providers (ADAS) observations
//Check every minute if Alerts are expired and power off.
var getProvidersObservationsJob = JobBuilder.Create<GetProvidersObservationsJob>()
.Build();
var getProvidersObservationsTrigger = TriggerBuilder.Create()
.StartNow()
.WithSimpleSchedule(x => x
.WithIntervalInMinutes(_getProviderObservationsIntervalMinutes)
.RepeatForever())
.Build();
//Job to get Providers (ADAS) observations
//Check every minute if Alerts are expired and power off.
var calculateNewsJob = JobBuilder.Create<CalculateNewsJob>()
.Build();
var calculateNewsJobTrigger = TriggerBuilder.Create()
.StartNow()
.WithSimpleSchedule(x => x
.WithIntervalInMinutes(_checkNewsJobIntervalMinutes)
.RepeatForever())
.StartNow()
.Build();
//Job to ArchiveNurseDataConfig
//Check every 15 minute if Patients has data to archive.
var archiveNurseDataJob = JobBuilder.Create<ArchiveNurseDataJob>()
.Build();
var archiveNurseDataJobTrigger = TriggerBuilder.Create()
.StartNow()
.WithSimpleSchedule(x => x
.WithIntervalInMinutes(_archiveNurseData.IntervalMinutes)
.RepeatForever())
.StartNow()
.Build();
var jobsDictionary = new Dictionary<IJobDetail, IReadOnlyCollection<ITrigger>>();
if (_activateCheckExpiredObservations)
jobsDictionary.Add(checkExpiredObservationsJob, new List<ITrigger> { checkExpiredObservationsTrigger });
if (_activateCheckExpiredAlerts)
jobsDictionary.Add(checkExpiredAlertsJob, new List<ITrigger> { checkExpiredAlertsTrigger });
if (_activateCheckInactivePatients)
jobsDictionary.Add(checkInactivePatientsJob, new List<ITrigger> { checkInactivePatientsTrigger });
if (_activateSchedulerCheckActiveTreatmentsJob)
jobsDictionary.Add(treatmentsJob, new List<ITrigger> { treatmentsTrigger });
if (_activateSchedulerCheckOpiateBoluses)
jobsDictionary.Add(opiateBolusesJob, new List<ITrigger> { opiateBolusesTrigger });
if (_activateSchedulerCheckHydricBalance)
jobsDictionary.Add(hydricBalanceJob, new List<ITrigger> { hydricBalanceTrigger });
if (_activateSchedulerGetProvidersObservations && _providersSettings.Value.Any())
jobsDictionary.Add(getProvidersObservationsJob, new List<ITrigger> { getProvidersObservationsTrigger });
if (_activateSchedulerCheckNewsJob)
jobsDictionary.Add(calculateNewsJob, new List<ITrigger> { calculateNewsJobTrigger });
if (_archiveNurseData.Active)
jobsDictionary.Add(archiveNurseDataJob, new List<ITrigger> { archiveNurseDataJobTrigger });
_logger.LogDebug("Tell to schedule the job using our trigger. {jobsDictionary}", jobsDictionary);
// Tell to schedule the job using our trigger
await scheduler.ScheduleJobs(jobsDictionary, true);
// and last shut down the scheduler when you are ready to close your program
//await scheduler.Shutdown();
}
}
[DisallowConcurrentExecution]
public class CheckHydricBalanceRyCJob : IJob
{
private readonly ILogger _logger = Log.ForContext<CheckHydricBalanceRyCJob>();
public static IObservationService ObservationService { get; set; } = null!;
public static IPatientService PatientService { get; set; } = null!;
public static ICalculatedObservationsService CalculatedObservationsService { get; set; } = null!;
public async Task Execute(IJobExecutionContext context)
{
var start = DateTime.Now;
//LogExecutionContext.TrySetTraceIdentifier(Guid.NewGuid().ToString(), true);
_logger.Debug("Start check hydric balance job");
try
{
var patients = await PatientService.FindAll();
foreach (var patient in patients)
{
var lastHydricBalance = await ObservationService.FindLastBeforeDate(patient.Id,
DateTime.UtcNow.AddMinutes(50), "Hydric_Balance");
if (lastHydricBalance != null &&
DateTime.Compare(
new DateTime(DateTime.UtcNow.Year, DateTime.UtcNow.Month, DateTime.UtcNow.Day,
DateTime.UtcNow.Hour, 0, 0),
new DateTime(lastHydricBalance.Time.Year, lastHydricBalance.Time.Month,
lastHydricBalance.Time.Day, lastHydricBalance.Time.Hour, 0, 0))
== 0
)
await CalculatedObservationsService.Map(lastHydricBalance);
}
}
catch (Exception ex)
{
_logger.Error("ERROR executing check hydric balance job {exMessage}", ex.Message);
}
var end = DateTime.Now;
_logger.Debug("Finished check hydric balance job in {TotalMilliseconds:F1} ms",
(end - start).TotalMilliseconds);
}
}
[DisallowConcurrentExecution]
public class CheckActiveTreatmentsJob : IJob
{
private readonly ILogger _logger = Log.ForContext<CheckActiveTreatmentsJob>();
public static ITreatmentService TreatmentService { get; set; } = null!;
public static IMedicineService MedicineService { get; set; } = null!;
public static IPatientService PatientService { get; set; } = null!;
public static ICalculatedObservationsService CalculatedObservationsService { get; set; } = null!;
public async Task Execute(IJobExecutionContext context)
{
var start = DateTime.Now;
//LogExecutionContext.TrySetTraceIdentifier(Guid.NewGuid().ToString(), true);
_logger.Debug("Executing check active treatments job");
try
{
var patients = await PatientService.FindAll();
foreach (var patient in patients)
{
var activeMedicines = new List<Medicine>();
//var treatments = treatmentService.GetActiveTreatmentsByPatient(patient.id);
var treatments =
await CalculatedObservationsService.GetActiveTreatmentsByPatient(patient.Id);
var medicines = await MedicineService.GetMedicinesOfTreatments(treatments);
var medicinesList = medicines.ToList();
var medicinesWithoutNutrition = medicinesList.Where(m => !m.Type.Contains("Nutrition"))
.ToList();
activeMedicines.AddRange(medicinesWithoutNutrition);
await CalculatedObservationsService.CalculateMedicineObservation(activeMedicines,
patient.Id);
}
}
catch (Exception ex)
{
_logger.Error("ERROR executing check active treatments job {exMessage}", ex.Message);
}
var end = DateTime.Now;
_logger.Debug("Finished check active treatments job in {TotalMilliseconds:F1} ms",
(end - start).TotalMilliseconds);
}
}
[DisallowConcurrentExecution]
public class CheckActiveAppointmentsJob : IJob
{
private readonly ILogger _logger = Log.ForContext<CheckActiveAppointmentsJob>();
public static IAppointmentService AppointmentService { get; set; } = null!;
public static IDiagnosisService DiagnosisService { get; set; } = null!;
public static IPatientService PatientService { get; set; } = null!;
public async Task Execute(IJobExecutionContext context)
{
var start = DateTime.Now;
_logger.Debug("Executing check active appointments job");
try
{
//TODO falta definir
}
catch (Exception ex)
{
_logger.Error("ERROR executing check active treatments job {exMessage}", ex.Message);
}
var end = DateTime.Now;
_logger.Debug("Finished check active treatments job in {TotalMilliseconds:F1} ms",
(end - start).TotalMilliseconds);
}
}
[DisallowConcurrentExecution]
public class CheckInactivePatientsJob : IJob
{
private readonly ILogger _logger = Log.ForContext<CheckInactivePatientsJob>();
public static IPatientService PatientService { get; set; } = null!;
public async Task Execute(IJobExecutionContext context)
{
//LogExecutionContext.TrySetTraceIdentifier(Guid.NewGuid().ToString(), true);
var start = DateTime.Now;
var dataMap = context.JobDetail.JobDataMap;
var archivePatientsWithoutObservationsSinceHours =
dataMap.GetInt("archivePatientsWithoutObservationsSinceHours");
var sinceDischargeTime = dataMap.GetInt("sinceDischargeTime");
var sinceDate = DateTime.Now.AddHours(-archivePatientsWithoutObservationsSinceHours);
_logger.Debug(
"Executing Check inactive patients job archivePatientsWithoutObservationsSinceHours: {archivePatientsWithoutObservationsSinceHours} sinceDate: {sinceDate} sinceDischargeTime: {sinceDischargeTime}",
archivePatientsWithoutObservationsSinceHours, sinceDate, sinceDischargeTime);
try
{
var exists = GlobalData.Data.TryGetValue("isCheckingInactivePatients", out var isChecking);
if (!exists || isChecking is false)
await PatientService.DischargeInactivePatients(sinceDate, sinceDischargeTime);
}
catch (Exception ex)
{
_logger.Error("ERROR executing check inactive patients job {ExMessage}", ex.Message);
}
var end = DateTime.Now;
_logger.Debug("Finished Check inactive patients job in {TotalMilliseconds:F1} ms",
(end - start).TotalMilliseconds);
}
}
[DisallowConcurrentExecution]
public class CheckOpiateBolusesJob : IJob
{
private readonly ILogger _logger = Log.ForContext<CheckOpiateBolusesJob>();
public static IPatientService PatientService { get; set; } = null!;
public static ICalculatedObservationsService CalculatedObservationsService { get; set; } = null!;
public async Task Execute(IJobExecutionContext context)
{
var start = DateTime.Now;
//LogExecutionContext.TrySetTraceIdentifier(Guid.NewGuid().ToString(), true);
_logger.Debug("Executing check opiate boluses job");
try
{
var patients = await PatientService.FindAll();
foreach (var patient in patients) await CalculatedObservationsService.CalculateBolusOpiates(patient.Id);
}
catch (Exception ex)
{
_logger.Error("ERROR executing check opiate boluses job {ExMessage} trace: {ExStackTrace}", ex.Message,
ex.StackTrace);
}
var end = DateTime.Now;
_logger.Debug("Finished Check opiate boluses job in {TotalSeconds:F1} seconds", (end - start).TotalSeconds);
}
}
[DisallowConcurrentExecution]
public class CheckExpiredObservationsJob : IJob
{
private readonly ILogger _logger = Log.ForContext<CheckExpiredObservationsJob>();
public static IObservationService ObservationService { get; set; } = null!;
public async Task Execute(IJobExecutionContext context)
{
var start = DateTime.Now;
//LogExecutionContext.TrySetTraceIdentifier(Guid.NewGuid().ToString(), true);
_logger.Debug("Executing check expired observations job");
try
{
var exists = GlobalData.Data.TryGetValue("isCheckingExpiration", out var isChecking);
if (!exists)
{
GlobalData.AddData("isCheckingExpiration", false);
isChecking = false;
}
if (!exists || isChecking is false) await ObservationService.ExpireObservationsAndRecalculateAsync();
}
catch (Exception ex)
{
_logger.Error("ERROR executing check expired observations {ExMessage} trace: {ExStackTrace}",
ex.Message, ex.StackTrace);
}
var end = DateTime.Now;
_logger.Debug("Finished Check expired observations job in {TotalSeconds:F1} seconds",
(end - start).TotalSeconds);
}
}
/// <summary>
/// Job for calculate NEWS based on FR, SPo2, Temperature, Tas and FC
/// </summary>
[DisallowConcurrentExecution]
public class CalculateNewsJob : IJob
{
private readonly ILogger _logger = Log.ForContext<CalculateNewsJob>();
public static IObservationService ObservationService { get; set; } = null!;
public static IConfigObservationService ConfigObservationService { get; set; } = null!;
public static IPatientService PatientService { get; set; } = null!;
public static int ExpiresIn { get; set; } = 15;
public async Task Execute(IJobExecutionContext context)
{
//Filter patients in real locations
//LogExecutionContext.TrySetTraceIdentifier(Guid.NewGuid().ToString(), true);
var patients = await PatientService.FindInActivePoC();
var observationList = new List<string> { "Resp_Rate_Calculated", "SpO2", "Temperature", "TAs", "FC" };
foreach (var patient in patients)
{
var observations =
await CheckExpiredAlertsJob.ObservationService.FindLastObservations(patient.Id, 1, observationList);
if (!observations.Any()) continue;
var newsScore = 0;
var msg = new StringBuilder();
_logger.Debug("CalculateNewsJob - patient ({patientPointOfCare} {patientBed})", patient.UnitString,
patient.Bed);
foreach (var obs in observations)
{
var conf = await ConfigObservationService.Get(obs);
var expires = conf?.Expires;
if (obs.Expired || (expires != null &&
obs.Time.AddSeconds(expires.Value).ToUniversalTime() < DateTime.UtcNow))
{
_logger.Verbose(
"CalculateNewsJob - patient ({patientPointOfCare} {patientBed}) obs ({obsName} value {obsValue} time {obsTime} expired {obsExpired}) confexpires: {expires} EXPIRED",
patient.UnitString, patient.Bed, obs.Name, obs.Value, obs.Time, obs.Expired, expires);
continue;
}
_logger.Verbose(
"CalculateNewsJob - patient ({patientPointOfCare} {patientBed}) obs ({obsName} value {obsValue} time {obsTime} expired {obsExpired}) confexpires: {expires} NOT EXPIRED",
patient.UnitString, patient.Bed, obs.Name, obs.Value, obs.Time, obs.Expired, expires);
var partialNewsScore = 0;
switch (obs.Name)
{
case "Resp_Rate_Calculated":
if (!double.TryParse(obs.Value.ToString(), out var frValue)) continue;
switch (Math.Round(frValue, 0))
{
case >= 12 and <= 20:
break;
case >= 25:
case <= 8:
partialNewsScore = 3;
break;
case >= 9 and <= 11:
partialNewsScore = 1;
break;
case >= 21 and <= 24:
partialNewsScore = 2;
break;
}
break;
case "SpO2":
if (!double.TryParse(obs.Value.ToString(), out var spo2Value)) continue;
switch (Math.Round(spo2Value, 0))
{
case <= 91:
partialNewsScore = 3;
break;
case >= 92 and <= 93:
partialNewsScore = 2;
break;
case >= 94 and <= 95:
partialNewsScore = 1;
break;
}
break;
case "Temperature":
if (!double.TryParse(obs.Value.ToString(), out var tempValue)) continue;
switch (Math.Round(tempValue, 1))
{
case <= 35:
partialNewsScore = 3;
break;
case >= 35.1 and <= 36.0:
case >= 38.1 and <= 39.0:
partialNewsScore = 1;
break;
case >= 39.1:
partialNewsScore = 2;
break;
}
break;
case "TAs":
if (!double.TryParse(obs.Value.ToString(), out var tasValue)) continue;
switch (Math.Round(tasValue, 0))
{
case <= 90:
case >= 220:
partialNewsScore = 3;
break;
case >= 91 and <= 100:
partialNewsScore = 2;
break;
case >= 101 and <= 110:
partialNewsScore = 1;
break;
}
break;
case "FC":
if (!double.TryParse(obs.Value.ToString(), out var fcValue)) continue;
switch (Math.Round(fcValue, 0))
{
case <= 40:
case >= 131:
partialNewsScore = 3;
break;
case >= 111 and <= 130:
partialNewsScore = 2;
break;
case >= 41 and <= 50:
case >= 91 and <= 110:
partialNewsScore = 1;
break;
}
break;
}
msg.Append($"[{obs.Name} {obs.Value} {partialNewsScore}] ");
newsScore += partialNewsScore;
}
var lastObs =
await CheckExpiredAlertsJob.ObservationService.FindLastObservations(patient.Id, 1, observationList);
if (lastObs.FirstOrDefault()?.Expired != true)
{
var newObs = new PatientObservation
{
Name = "NEWS",
CodingSystem = "ADAS",
Expires = ExpiresIn,
Value = newsScore,
PatientId = patient.Id,
Time = DateTime.Now
};
await CheckExpiredAlertsJob.ObservationService.InsertObservation(newObs);
_logger.Debug(
$"CalculateNewsJob - patient ({patient.UnitString} {patient.Bed}) newsScore: {newsScore} from {msg}");
}
}
}
}
[DisallowConcurrentExecution]
public class CheckExpiredAlertsJob : IJob
{
private readonly ILogger _logger = Log.ForContext<CheckExpiredAlertsJob>();
public static IObservationService ObservationService { get; set; } = null!;
public async Task Execute(IJobExecutionContext context)
{
var start = DateTime.Now;
//LogExecutionContext.TrySetTraceIdentifier(Guid.NewGuid().ToString(), true);
_logger.Debug("Executing check expired alerts and power off job");
try
{
var exists = GlobalData.Data.TryGetValue("isCheckingAlertsExpiration", out var isChecking);
if (!exists || isChecking is false) await ObservationService.ExpireAlertsAndPowerOffAsync();
}
catch (Exception ex)
{
_logger.Error("ERROR executing check expired alerts and power off {ExMessage} trace: {ExStackTrace}",
ex.Message,
ex.StackTrace);
}
var end = DateTime.Now;
_logger.Debug("Finished Check check expired alerts and power off job in {TotalSeconds:F1} seconds",
(end - start).TotalSeconds);
}
}
[DisallowConcurrentExecution]
public class ArchiveNurseDataJob : IJob
{
private readonly ILogger _logger = Log.ForContext<CheckOpiateBolusesJob>();
//private readonly ArchiveNurseData _archiveNurseData;
public static ArchiveNurseData ArchiveNurseDataSettings { get; set; } = new();
public static IPatientService PatientService { get; set; } = null!;
public static IPatientCarePlanService PatientCarePlanService { get; set; } = null!;
public async Task Execute(IJobExecutionContext context)
{
var start = DateTime.Now;
_logger.Debug("Executing ArchiveNurseDataJob job");
try
{
if (ArchiveNurseDataSettings.ArchiveProcedure.Active)
{
var patientWithFinishedProcedures =
await PatientService.FindAllPatientWithFinishedProcedures(ArchiveNurseDataSettings.ArchiveProcedure
.EndDateAfterMinutes);
foreach (var patientWithFinishedProcedure in patientWithFinishedProcedures)
{
var itemsToArchive = patientWithFinishedProcedure.Procedures?
.Where(c =>
c is
{
//OptionType: "procedure",
EndDate: not null
} &&
c.EndDate.Value.AddMinutes(ArchiveNurseDataSettings.ArchiveProcedure.EndDateAfterMinutes) <
DateTime.UtcNow)
.ToList();
if (itemsToArchive != null)
{
_ = PatientCarePlanService.ArchiveCarePlanFromJob(patientWithFinishedProcedure,
itemsToArchive);
patientWithFinishedProcedure.Procedures = patientWithFinishedProcedure.Procedures?
.Where(c => !itemsToArchive.Contains(c)).ToList();
await PatientService.Update(patientWithFinishedProcedure);
}
}
}
if (ArchiveNurseDataSettings.ArchiveTest.Active)
{
var patientWithFinishedTests =
await PatientService.FindAllPatientWithFinishedTest(ArchiveNurseDataSettings.ArchiveTest
.EndDateAfterMinutes);
foreach (var patientWithFinishedTest in patientWithFinishedTests)
{
var itemsToArchive = patientWithFinishedTest.Tests?
.Where(c =>
c is
{
//OptionType: "test",
EndDate: not null
} &&
c.EndDate.Value.AddMinutes(ArchiveNurseDataSettings.ArchiveTest.EndDateAfterMinutes) <
DateTime.UtcNow)
.ToList();
if (itemsToArchive != null)
{
_ = PatientCarePlanService.ArchiveCarePlanFromJob(patientWithFinishedTest,
itemsToArchive);
patientWithFinishedTest.Tests = patientWithFinishedTest.Tests?
.Where(c => !itemsToArchive.Contains(c)).ToList();
await PatientService.Update(patientWithFinishedTest);
}
}
}
if (ArchiveNurseDataSettings.ArchiveTreatment.Active)
{
var patientWithFinishedTreatments =
await PatientService.FindAllPatientWithFinishedTreatment(ArchiveNurseDataSettings.ArchiveTreatment
.EndDateAfterMinutes);
foreach (var patientWithFinishedTreatment in patientWithFinishedTreatments)
{
var itemsToArchive = patientWithFinishedTreatment.Treatment?
.Where(c =>
c.EndDate.HasValue &&
c.EndDate.Value.AddMinutes(ArchiveNurseDataSettings.ArchiveTest.EndDateAfterMinutes) <
DateTime.UtcNow)
.ToList();
if (itemsToArchive != null)
{
_ = PatientCarePlanService.ArchiveCarePlanFromJob(patientWithFinishedTreatment,
itemsToArchive);
patientWithFinishedTreatment.Treatment = patientWithFinishedTreatment.Treatment?
.Where(c => !itemsToArchive.Contains(c))
.ToList();
await PatientService.Update(patientWithFinishedTreatment);
}
}
}
}
catch (Exception ex)
{
_logger.Error("ERROR executing ArchiveNurseDataJob {ExMessage} trace: {ExStackTrace}",
ex.Message,
ex.StackTrace);
}
var end = DateTime.Now;
_logger.Debug("Finished ArchiveNurseDataJob {TotalSeconds:F1} seconds",
(end - start).TotalSeconds);
}
}
[DisallowConcurrentExecution]
public class GetProvidersObservationsJob : IJob
{
private readonly ILogger _logger = Log.ForContext<GetProvidersObservationsJob>();
public static IObservationService ObservationService { get; set; } = null!;
public static IPatientService PatientService { get; set; } = null!;
public static List<ProvidersSettings> Providers { get; set; } = null!;
public static IHttpClientFactory HttpClientFactory { get; set; } = null!;
public async Task Execute(IJobExecutionContext context)
{
var start = DateTime.Now;
_logger.Debug("Executing get providers job");
try
{
if (!Providers.Any()) return;
foreach (var provider in Providers)
{
//replace - to _ to fit name
var providerType =
Type.GetType(
$"{Assembly.GetExecutingAssembly().GetName().Name?.Replace("-", "_")}.Providers.{provider.Name}Provider");
if (providerType == null)
{
Log.Error("Provider {ProviderName} not able lo load by reflection", provider.Name);
continue;
}
var ctor = providerType.GetConstructor([
typeof(IOptions<ProvidersSettings>),
typeof(IHttpClientFactory)
]);
if (ctor == null)
{
Log.Error("not able to find constructor for provider: {ProviderName}", provider.Name);
continue;
}
var customProvider = (BaseProvider)ctor.Invoke([
Options.Create(provider),
HttpClientFactory
]);
var patients = await PatientService.FindAll();
foreach (var patient in patients)
{
var observations = await customProvider.GetObservations(patient);
if (observations.Any()) observations.ForEach(o => ObservationService.InsertObservation(o));
}
}
}
catch (Exception ex)
{
_logger.Error(
"ERROR executing GetByCodeSysAndCode providers observations job error: {ExMessage} trace: {ExStackTrace}",
ex.Message, ex.StackTrace);
}
var end = DateTime.Now;
_logger.Debug("Finished GetByCodeSysAndCode providers observations job in {TotalMilliseconds:F1} ms",
(end - start).TotalMilliseconds);
}
}