Refactored Indexer models

This commit is contained in:
2025-08-31 00:11:05 +02:00
parent 8a3be8dd90
commit 2a75daee07
16 changed files with 591 additions and 591 deletions

317
src/Indexer/Calls.cs Normal file
View File

@@ -0,0 +1,317 @@
using Microsoft.Extensions.Diagnostics.HealthChecks;
using Indexer.Models;
using Indexer.Exceptions;
using Quartz;
using Quartz.Impl;
public class RunOnceCall : ICall
{
public ILogger _logger;
public bool IsEnabled { get; set; }
public bool IsExecuting { get; set; }
public Worker Worker { get; }
public CallConfig CallConfig { get; set; }
public DateTime? LastExecution { get; set; }
public DateTime? LastSuccessfulExecution { get; set; }
public RunOnceCall(Worker worker, ILogger logger, CallConfig callConfig)
{
Worker = worker;
_logger = logger;
CallConfig = callConfig;
IsEnabled = true;
IsExecuting = false;
IndexAsync();
}
public void Start()
{
IndexAsync();
IsEnabled = true;
}
public void Stop()
{
IsEnabled = false;
}
private async void IndexAsync()
{
try
{
DateTime beforeExecution = DateTime.Now;
IsExecuting = true;
try
{
await Task.Run(() => Worker.Scriptable.Update(new RunOnceCallbackInfos()));
}
finally
{
IsExecuting = false;
LastExecution = beforeExecution;
Worker.LastExecution = beforeExecution;
}
DateTime afterExecution = DateTime.Now;
WorkerManager.UpdateCallAndWorkerTimestamps(this, Worker, beforeExecution, afterExecution);
}
catch (Exception ex)
{
_logger.LogError("Exception occurred in a Call of Worker \"{name}\": \"{ex}\"", Worker.Name, ex.Message);
}
}
public HealthCheckResult HealthCheck()
{
return HealthCheckResult.Healthy(); // TODO implement proper healthcheck
}
}
public class IntervalCall : ICall
{
public System.Timers.Timer Timer;
public IScriptable Scriptable;
public ILogger _logger;
public bool IsEnabled { get; set; }
public bool IsExecuting { get; set; }
public CallConfig CallConfig { get; set; }
public DateTime? LastExecution { get; set; }
public DateTime? LastSuccessfulExecution { get; set; }
public IntervalCall(System.Timers.Timer timer, IScriptable scriptable, ILogger logger, CallConfig callConfig)
{
Timer = timer;
Scriptable = scriptable;
_logger = logger;
CallConfig = callConfig;
IsEnabled = true;
IsExecuting = false;
}
public void Start()
{
Timer.Start();
IsEnabled = true;
}
public void Stop()
{
Scriptable.Stop();
Timer.Stop();
IsEnabled = false;
}
public HealthCheckResult HealthCheck()
{
if (!Scriptable.UpdateInfo.Successful)
{
_logger.LogWarning("HealthCheck revealed: The last execution of \"{name}\" was not successful", Scriptable.ToolSet.FilePath);
return HealthCheckResult.Unhealthy($"HealthCheck revealed: The last execution of \"{Scriptable.ToolSet.FilePath}\" was not successful");
}
double timerInterval = Timer.Interval; // In ms
DateTime lastRunDateTime = Scriptable.UpdateInfo.DateTime;
DateTime now = DateTime.Now;
double millisecondsSinceLastExecution = now.Subtract(lastRunDateTime).TotalMilliseconds;
if (millisecondsSinceLastExecution >= 2 * timerInterval)
{
_logger.LogWarning("HealthCheck revealed: Since the last execution of \"{name}\" more than twice the interval has passed", Scriptable.ToolSet.FilePath);
return HealthCheckResult.Unhealthy($"HealthCheck revealed: Since the last execution of \"{Scriptable.ToolSet.FilePath}\" more than twice the interval has passed");
}
return HealthCheckResult.Healthy();
}
}
public class ScheduleCall : ICall
{
public bool IsEnabled { get; set; }
public bool IsExecuting { get; set; }
public Worker Worker { get; }
public JobKey JobKey { get; }
public JobDataMap JobDataMap { get; }
public CallConfig CallConfig { get; set; }
private ILogger _logger { get; }
public DateTime? LastExecution { get; set; }
public DateTime? LastSuccessfulExecution { get; set; }
private StdSchedulerFactory SchedulerFactory { get; }
private IScheduler Scheduler { get; }
public ScheduleCall(Worker worker, CallConfig callConfig, ILogger logger)
{
Worker = worker;
CallConfig = callConfig;
_logger = logger;
IsEnabled = false;
IsExecuting = false;
JobKey = new(worker.Name);
SchedulerFactory = new();
Scheduler = SchedulerFactory.GetScheduler(CancellationToken.None).Result;
JobDataMap = [];
JobDataMap["action"] = () =>
{
try
{
DateTime beforeExecution = DateTime.Now;
IsExecuting = true;
try
{
worker.Scriptable.Update(new ScheduleCallbackInfos());
}
finally
{
IsExecuting = false;
LastExecution = beforeExecution;
worker.LastExecution = beforeExecution;
}
DateTime afterExecution = DateTime.Now;
WorkerManager.UpdateCallAndWorkerTimestamps(this, worker, beforeExecution, afterExecution);
}
catch (Exception ex)
{
_logger.LogError("Exception occurred in a Call of Worker \"{name}\": \"{ex}\"", worker.Name, ex.Message);
}
};
CreateJob().Wait();
Start();
}
public void Start()
{
if (!IsEnabled)
{
Scheduler.Start(CancellationToken.None).Wait();
IsEnabled = true;
}
}
public void Stop()
{
Scheduler.PauseAll();
IsEnabled = false;
}
private async Task CreateJob()
{
if (CallConfig.Schedule is null)
{
throw new IndexerConfigurationException($"Interval not set for a Call in Worker \"{Worker.Name}\"");
}
try
{
await Scheduler.ScheduleJob(
JobBuilder.Create<ActionJob>()
.WithIdentity(JobKey)
.Build(),
TriggerBuilder.Create()
.ForJob(JobKey)
.WithIdentity(Worker.Name + "-trigger")
.UsingJobData(JobDataMap)
.WithCronSchedule(CallConfig.Schedule)
.Build(),
CancellationToken.None);
}
catch (FormatException)
{
throw new IndexerConfigurationException($"Quartz Cron expression invalid in Worker \"{Worker.Name}\" - Quartz syntax differs from classic cron");
}
}
public HealthCheckResult HealthCheck()
{
return HealthCheckResult.Unhealthy(); // Not implemented yet
}
}
public class FileUpdateCall : ICall
{
public bool IsEnabled { get; set; }
public bool IsExecuting { get; set; }
public Worker Worker { get; }
public CallConfig CallConfig { get; set; }
private ILogger _logger { get; }
private FileSystemWatcher _watcher { get; }
public DateTime? LastExecution { get; set; }
public DateTime? LastSuccessfulExecution { get; set; }
public FileUpdateCall(Worker worker, CallConfig callConfig, ILogger logger)
{
Worker = worker;
CallConfig = callConfig;
_logger = logger;
IsEnabled = true;
IsExecuting = false;
if (CallConfig.Path is null)
{
throw new IndexerConfigurationException($"Path not set for a Call in Worker \"{Worker.Name}\"");
}
_watcher = new FileSystemWatcher(CallConfig.Path);
_watcher.Changed += OnFileChanged;
_watcher.Deleted += OnFileChanged;
_watcher.EnableRaisingEvents = true;
}
public void Start()
{
if (!IsEnabled)
{
IsEnabled = true;
_watcher.EnableRaisingEvents = true;
Index();
}
}
public void Stop()
{
if (IsEnabled)
{
IsEnabled = false;
_watcher.EnableRaisingEvents = false;
}
}
private void OnFileChanged(object sender, FileSystemEventArgs e)
{
if (!IsEnabled)
{
return;
}
Index(sender, e);
}
private void Index(object? sender, FileSystemEventArgs? e)
{
try
{
DateTime beforeExecution = DateTime.Now;
IsExecuting = true;
try
{
Worker.Scriptable.Update(new FileUpdateCallbackInfos() {sender = sender, e = e});
}
finally
{
IsExecuting = false;
LastExecution = beforeExecution;
Worker.LastExecution = beforeExecution;
}
DateTime afterExecution = DateTime.Now;
WorkerManager.UpdateCallAndWorkerTimestamps(this, Worker, beforeExecution, afterExecution);
}
catch (Exception ex)
{
_logger.LogError("Exception occurred in a Call of Worker \"{name}\": \"{ex}\"", Worker.Name, ex.Message);
}
}
private void Index()
{
Index(null, null);
}
public HealthCheckResult HealthCheck()
{
return HealthCheckResult.Unhealthy(); // Not implemented yet
}
}