diff --git a/src/Indexer/Calls.cs b/src/Indexer/Calls.cs index 57a384e..af9da78 100644 --- a/src/Indexer/Calls.cs +++ b/src/Indexer/Calls.cs @@ -8,6 +8,7 @@ public class RunOnceCall : ICall public ILogger _logger; public bool IsEnabled { get; set; } public bool IsExecuting { get; set; } + public string Name { get; set; } public Worker Worker { get; } public CallConfig CallConfig { get; set; } public DateTime? LastExecution { get; set; } @@ -20,6 +21,7 @@ public class RunOnceCall : ICall CallConfig = callConfig; IsEnabled = true; IsExecuting = false; + Name = callConfig.Name; IndexAsync(); } @@ -34,6 +36,8 @@ public class RunOnceCall : ICall IsEnabled = false; } + public void Dispose() {} + private async void IndexAsync() { try @@ -73,6 +77,7 @@ public class IntervalCall : ICall public ILogger _logger; public bool IsEnabled { get; set; } public bool IsExecuting { get; set; } + public string Name { get; set; } public CallConfig CallConfig { get; set; } public DateTime? LastExecution { get; set; } public DateTime? LastSuccessfulExecution { get; set; } @@ -84,6 +89,7 @@ public class IntervalCall : ICall CallConfig = callConfig; IsEnabled = true; IsExecuting = false; + Name = callConfig.Name; if (callConfig.Interval is null) { _logger.LogError("Interval not set for a Call in Worker \"{Name}\"", worker.Name); @@ -134,6 +140,10 @@ public class IntervalCall : ICall Timer.Stop(); IsEnabled = false; } + public void Dispose() + { + Timer.Dispose(); + } public HealthCheckResult HealthCheck() { @@ -160,6 +170,7 @@ public class ScheduleCall : ICall { public bool IsEnabled { get; set; } public bool IsExecuting { get; set; } + public string Name { get; set; } public Worker Worker { get; } public JobKey JobKey { get; } public JobDataMap JobDataMap { get; } @@ -177,6 +188,7 @@ public class ScheduleCall : ICall _logger = logger; IsEnabled = false; IsExecuting = false; + Name = callConfig.Name; JobKey = new(worker.Name); SchedulerFactory = new(); Scheduler = SchedulerFactory.GetScheduler(CancellationToken.None).Result; @@ -224,6 +236,10 @@ public class ScheduleCall : ICall IsEnabled = false; } + public void Dispose() + { + Scheduler.DeleteJob(JobKey); + } private async Task CreateJob() { @@ -262,6 +278,7 @@ public class FileUpdateCall : ICall { public bool IsEnabled { get; set; } public bool IsExecuting { get; set; } + public string Name { get; set; } public Worker Worker { get; } public CallConfig CallConfig { get; set; } private ILogger _logger { get; } @@ -276,6 +293,7 @@ public class FileUpdateCall : ICall _logger = logger; IsEnabled = true; IsExecuting = false; + Name = callConfig.Name; if (CallConfig.Path is null) { throw new IndexerConfigurationException($"Path not set for a Call in Worker \"{Worker.Name}\""); @@ -318,6 +336,10 @@ public class FileUpdateCall : ICall } } + public void Dispose() + { + _watcher.Dispose(); + } private void OnFileChanged(object sender, FileSystemEventArgs e) { diff --git a/src/Indexer/Controllers/CallsController.cs b/src/Indexer/Controllers/CallsController.cs index 236bb39..a5e3660 100644 --- a/src/Indexer/Controllers/CallsController.cs +++ b/src/Indexer/Controllers/CallsController.cs @@ -22,17 +22,17 @@ public class CallsController : ControllerBase } [HttpGet("List")] - public ActionResult List(string name) + public ActionResult List(string workerName) { bool success = true; List calls = []; var configWorkerSection = _config.GetSection("EmbeddingsearchIndexer:Worker"); - _workerCollection.Workers.TryGetValue(name, out Worker? worker); + _workerCollection.Workers.TryGetValue(workerName, out Worker? worker); if (worker is null) { success = false; - _logger.LogError("No worker found under the name {name}.", [name]); - HttpContext.RaiseError(new Exception($"No worker found under the name {name}")); + _logger.LogError("No worker found under the name {name}.", [workerName]); + HttpContext.RaiseError(new Exception($"No worker found under the name {workerName}")); } else { @@ -54,70 +54,67 @@ public class CallsController : ControllerBase } [HttpGet("Enable")] - public ActionResult Enable(string name) + public ActionResult Enable(string workerName, string? callName) { - _workerCollection.Workers.TryGetValue(name, out Worker? worker); + _workerCollection.Workers.TryGetValue(workerName, out Worker? worker); if (worker is null) { - _logger.LogError("Unable to start calls in worker {name} - no running worker with this name.", [name]); - return new WorkerStartResult { Success = false }; + _logger.LogError("Unable to start calls in worker {workerName} - no running worker with this name.", [workerName]); + return new CallEnableResult { Success = false }; } - _logger.LogInformation("Starting calls in worker {name}.", [name]); - foreach (ICall call in worker.Calls) + if (callName is null) { + _logger.LogInformation("Starting calls in worker {workerName}.", [workerName]); + foreach (ICall call in worker.Calls) + { + call.Start(); + } + _logger.LogInformation("Finished starting calls in worker {workerName}.", [workerName]); + } + else + { + _logger.LogCritical(worker.Calls.First().Name); + ICall? call = worker.Calls.Where(x => x.Name == callName).SingleOrDefault(); + if (call is null) + { + _logger.LogError("Unable to start call {callName} in worker {workerName} - no call with this name.", [callName, workerName]); + return new CallEnableResult { Success = false }; + } + _logger.LogInformation("Starting call {callName} in worker {workerName}.", [callName, workerName]); call.Start(); } - _logger.LogInformation("Starting calls in worker {name}.", [name]); - return new WorkerStartResult { Success = true }; + return new CallEnableResult { Success = true }; } [HttpGet("Disable")] - public ActionResult Disable(string name) + public ActionResult Disable(string workerName, string? callName) { - _workerCollection.Workers.TryGetValue(name, out Worker? worker); + _workerCollection.Workers.TryGetValue(workerName, out Worker? worker); if (worker is null) { - _logger.LogError("Unable to stop calls in worker {name} - no running worker with this name.", [name]); - return new WorkerStopResult { Success = false }; + _logger.LogError("Unable to stop calls in worker {name} - no running worker with this name.", [workerName]); + return new CallDisableResult { Success = false }; } - _logger.LogInformation("Stopping calls in worker {name}.", [name]); - foreach (ICall call in worker.Calls) + if (callName is null) { - call.Stop(); - } - _logger.LogInformation("Stopped calls in worker {name}.", [name]); - return new WorkerStopResult { Success = true }; - } - - [HttpGet("Reload")] - public ActionResult Reload() - { - try - { - _logger.LogInformation("Reloading configuration"); - _configurationRoot.Reload(); - _logger.LogInformation("Reloaded configuration"); - _logger.LogInformation("Destroying workers"); - foreach (KeyValuePair workerKVPair in _workerCollection.Workers) + _logger.LogInformation("Stopping calls in worker {name}.", [workerName]); + foreach (ICall call in worker.Calls) { - Worker worker = workerKVPair.Value; - foreach (ICall call in worker.Calls) - { - call.Stop(); - } - _workerCollection.Workers.Remove(workerKVPair.Key); - _logger.LogInformation("Destroyed worker {workerKVPair.Key}", [workerKVPair.Key]); + call.Stop(); } - _logger.LogInformation("Destroyed workers"); - _workerCollection.InitializeWorkers(); - return new WorkerReloadConfigResult { Success = true }; - } - catch (Exception ex) + _logger.LogInformation("Stopped calls in worker {name}.", [workerName]); + } else { - _logger.LogError("Exception {ex.Message} happened while trying to reload the worker configuration.", [ex.Message]); - HttpContext.RaiseError(ex); - return new WorkerReloadConfigResult { Success = false }; + _logger.LogCritical(worker.Calls.First().Name); + ICall? call = worker.Calls.Where(x => x.Name == callName).SingleOrDefault(); + if (call is null) + { + _logger.LogError("Unable to start call {callName} in worker {workerName} - no call with this name.", [callName, workerName]); + return new CallDisableResult { Success = false }; + } + _logger.LogInformation("Starting call {callName} in worker {workerName}.", [callName, workerName]); + call.Stop(); } + return new CallDisableResult { Success = true }; } - } diff --git a/src/Indexer/Controllers/ConfigController.cs b/src/Indexer/Controllers/ConfigController.cs new file mode 100644 index 0000000..8933bad --- /dev/null +++ b/src/Indexer/Controllers/ConfigController.cs @@ -0,0 +1,58 @@ +using ElmahCore; +using Microsoft.AspNetCore.Mvc; +using Indexer.Models; + +namespace Indexer.Controllers; + + +[ApiController] +[Route("[controller]")] +public class ConfigController : ControllerBase +{ + private readonly ILogger _logger; + private readonly IConfiguration _config; + private readonly IConfigurationRoot _configurationRoot; + private readonly WorkerManager _workerCollection; + + public ConfigController(ILogger logger, IConfiguration config, IConfigurationRoot configurationRoot, WorkerManager workerCollection) + { + _logger = logger; + _config = config; + _configurationRoot = configurationRoot; + _workerCollection = workerCollection; + } + + [HttpGet("Reload")] + public ActionResult Reload() + { + try + { + _logger.LogInformation("Reloading configuration"); + _configurationRoot.Reload(); + _logger.LogInformation("Reloaded configuration"); + _logger.LogInformation("Destroying workers"); + foreach (KeyValuePair workerKVPair in _workerCollection.Workers) + { + Worker worker = workerKVPair.Value; + foreach (ICall call in worker.Calls) + { + call.Stop(); + call.Dispose(); + } + worker.Calls.Clear(); + + _workerCollection.Workers.Remove(workerKVPair.Key); + _logger.LogInformation("Destroyed worker {workerKVPair.Key}", [workerKVPair.Key]); + } + _logger.LogInformation("Destroyed workers"); + _workerCollection.InitializeWorkers(); + return new ConfigReloadResult { Success = true }; + } + catch (Exception ex) + { + _logger.LogError("Exception {ex.Message} happened while trying to reload the worker configuration.", [ex.Message]); + HttpContext.RaiseError(ex); + return new ConfigReloadResult { Success = false }; + } + } +} \ No newline at end of file diff --git a/src/Indexer/Models/CallModels.cs b/src/Indexer/Models/CallModels.cs index 00314f0..56f1888 100644 --- a/src/Indexer/Models/CallModels.cs +++ b/src/Indexer/Models/CallModels.cs @@ -4,6 +4,7 @@ namespace Indexer.Models; public class CallConfig { + public required string Name { get; set; } public required string Type { get; set; } public long? Interval { get; set; } // For Type: Interval public string? Path { get; set; } // For Type: FileSystemWatcher @@ -17,6 +18,8 @@ public interface ICall public HealthCheckResult HealthCheck(); public void Start(); public void Stop(); + public void Dispose(); + public string Name { get; set; } public bool IsEnabled { get; set; } public bool IsExecuting { get; set; } public CallConfig CallConfig { get; set; } diff --git a/src/Indexer/Models/CallResultModels.cs b/src/Indexer/Models/CallResultModels.cs new file mode 100644 index 0000000..05b1f37 --- /dev/null +++ b/src/Indexer/Models/CallResultModels.cs @@ -0,0 +1,39 @@ +using System.Text.Json.Serialization; + +namespace Indexer.Models; + +public class CallListResults +{ + [JsonPropertyName("Calls")] + public required List Calls { get; set; } + [JsonPropertyName("Success")] + public required bool Success { get; set; } +} + +public class CallListResult +{ + [JsonPropertyName("CallConfig")] + public required CallConfig CallConfig { get; set; } + [JsonPropertyName("IsActive")] + public required bool IsActive { get; set; } + [JsonPropertyName("IsExecuting")] + public required bool IsExecuting { get; set; } + [JsonPropertyName("LastExecution")] + public required DateTime? LastExecution { get; set; } + [JsonPropertyName("LastSuccessfulExecution")] + public required DateTime? LastSuccessfulExecution { get; set; } + [JsonPropertyName("HealthStatus")] + public required string HealthStatus { get; set; } +} + +public class CallDisableResult +{ + [JsonPropertyName("Success")] + public required bool Success { get; set; } +} + +public class CallEnableResult +{ + [JsonPropertyName("Success")] + public required bool Success { get; set; } +} \ No newline at end of file diff --git a/src/Indexer/Models/ConfigResultModels.cs b/src/Indexer/Models/ConfigResultModels.cs new file mode 100644 index 0000000..5e2501b --- /dev/null +++ b/src/Indexer/Models/ConfigResultModels.cs @@ -0,0 +1,9 @@ +using System.Text.Json.Serialization; + +namespace Indexer.Models; + +public class ConfigReloadResult +{ + [JsonPropertyName("Success")] + public required bool Success { get; set; } +} diff --git a/src/Indexer/Models/WorkerResultModels.cs b/src/Indexer/Models/WorkerResultModels.cs index 3f588e4..0d39225 100644 --- a/src/Indexer/Models/WorkerResultModels.cs +++ b/src/Indexer/Models/WorkerResultModels.cs @@ -26,50 +26,8 @@ public class WorkerListResult public required string HealthStatus { get; set; } } -public class CallListResults -{ - [JsonPropertyName("Calls")] - public required List Calls { get; set; } - [JsonPropertyName("Success")] - public required bool Success { get; set; } -} - -public class CallListResult -{ - [JsonPropertyName("CallConfig")] - public required CallConfig CallConfig { get; set; } - [JsonPropertyName("IsActive")] - public required bool IsActive { get; set; } - [JsonPropertyName("IsExecuting")] - public required bool IsExecuting { get; set; } - [JsonPropertyName("LastExecution")] - public required DateTime? LastExecution { get; set; } - [JsonPropertyName("LastSuccessfulExecution")] - public required DateTime? LastSuccessfulExecution { get; set; } - [JsonPropertyName("HealthStatus")] - public required string HealthStatus { get; set; } -} - -public class WorkerStopResult -{ - [JsonPropertyName("Success")] - public required bool Success { get; set; } -} - -public class WorkerStartResult -{ - [JsonPropertyName("Success")] - public required bool Success { get; set; } -} - public class WorkerTriggerUpdateResult { [JsonPropertyName("Success")] public required bool Success { get; set; } -} - -public class WorkerReloadConfigResult -{ - [JsonPropertyName("Success")] - public required bool Success { get; set; } -} +} \ No newline at end of file diff --git a/src/Indexer/appsettings.Development.json b/src/Indexer/appsettings.Development.json index 2a7d06c..59651ef 100644 --- a/src/Indexer/appsettings.Development.json +++ b/src/Indexer/appsettings.Development.json @@ -16,6 +16,7 @@ "Script": "Scripts/example.py", "Calls": [ { + "Name": "intervalCall", "Type": "interval", "Interval": 30000 } @@ -26,13 +27,16 @@ "Script": "Scripts/example.csx", "Calls": [ { + "Name": "runonceCall", "Type": "runonce" }, { + "Name": "scheduleCall", "Type": "schedule", "Schedule": "0 0/5 * * * ?" }, { + "Name": "fileupdateCall", "Type": "fileupdate", "Path": "./Scripts/example_content", "Events": ["Created", "Changed", "Deleted", "Renamed"],