1006 lines
41 KiB
C#
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);
|
|
}
|
|
} |