diff --git a/API/Tranga.cs b/API/Tranga.cs index 406fb15..829c5d5 100644 --- a/API/Tranga.cs +++ b/API/Tranga.cs @@ -123,24 +123,25 @@ public static class Tranga Log.Fatal("ServiceProvider is null"); return; } - Action callBack = AfterWork(worker, callback); + Action afterWorkCallback = AfterWork(worker, callback); + if (worker is BaseWorkerWithContext mangaContextWorker) { mangaContextWorker.SetScope(ServiceProvider.CreateScope()); - RunningWorkers.TryAdd(mangaContextWorker, mangaContextWorker.DoWork(callBack)); + RunningWorkers.TryAdd(mangaContextWorker, mangaContextWorker.DoWork(afterWorkCallback)); }else if (worker is BaseWorkerWithContext notificationContextWorker) { notificationContextWorker.SetScope(ServiceProvider.CreateScope()); - RunningWorkers.TryAdd(notificationContextWorker, notificationContextWorker.DoWork(callBack)); + RunningWorkers.TryAdd(notificationContextWorker, notificationContextWorker.DoWork(afterWorkCallback)); }else if (worker is BaseWorkerWithContext libraryContextWorker) { libraryContextWorker.SetScope(ServiceProvider.CreateScope()); - RunningWorkers.TryAdd(libraryContextWorker, libraryContextWorker.DoWork(callBack)); + RunningWorkers.TryAdd(libraryContextWorker, libraryContextWorker.DoWork(afterWorkCallback)); }else - RunningWorkers.TryAdd(worker, worker.DoWork(callBack)); + RunningWorkers.TryAdd(worker, worker.DoWork(afterWorkCallback)); } - private static Action AfterWork(BaseWorker worker, Action? callback) => () => + private static Action AfterWork(BaseWorker worker, Action? callback = null) => () => { Log.Debug($"AfterWork {worker}"); RunningWorkers.Remove(worker, out _); diff --git a/API/Workers/BaseWorker.cs b/API/Workers/BaseWorker.cs index 68f43db..39ef2d9 100644 --- a/API/Workers/BaseWorker.cs +++ b/API/Workers/BaseWorker.cs @@ -23,7 +23,7 @@ public abstract class BaseWorker : Identifiable public IEnumerable MissingDependencies => DependsOn.Where(d => d.State < WorkerExecutionState.Completed); public bool AllDependenciesFulfilled => DependsOn.All(d => d.State >= WorkerExecutionState.Completed); internal WorkerExecutionState State { get; private set; } - private static readonly CancellationTokenSource CancellationTokenSource = new(TimeSpan.FromMinutes(10)); + private CancellationTokenSource? CancellationTokenSource = null; protected ILog Log { get; init; } /// @@ -33,7 +33,7 @@ public abstract class BaseWorker : Identifiable { Log.Debug($"Cancelled {this}"); this.State = WorkerExecutionState.Cancelled; - CancellationTokenSource.Cancel(); + CancellationTokenSource?.Cancel(); } /// @@ -43,7 +43,7 @@ public abstract class BaseWorker : Identifiable { Log.Debug($"Failed {this}"); this.State = WorkerExecutionState.Failed; - CancellationTokenSource.Cancel(); + CancellationTokenSource?.Cancel(); } public BaseWorker(IEnumerable? dependsOn = null) @@ -70,9 +70,12 @@ public abstract class BaseWorker : Identifiable /// public Task DoWork(Action? callback = null) { + // Start the worker Log.Debug($"Checking {this}"); + this.CancellationTokenSource = new(TimeSpan.FromMinutes(10)); this.State = WorkerExecutionState.Waiting; + // Wait for dependencies, start them if necessary BaseWorker[] missingDependenciesThatNeedStarting = MissingDependencies.Where(d => d.State < WorkerExecutionState.Waiting).ToArray(); if(missingDependenciesThatNeedStarting.Any()) return new Task(() => missingDependenciesThatNeedStarting); @@ -80,29 +83,32 @@ public abstract class BaseWorker : Identifiable if (MissingDependencies.Any()) return new Task(WaitForDependencies); + // Run the actual work Log.Info($"Running {this}"); DateTime startTime = DateTime.UtcNow; Task task = new (DoWorkInternal, CancellationTokenSource.Token); - task.GetAwaiter().OnCompleted(() => - { - DateTime endTime = DateTime.UtcNow; - Log.Info($"Completed {this}\n\t{endTime.Subtract(startTime).TotalMilliseconds} ms"); - this.State = WorkerExecutionState.Completed; - if(this is IPeriodic periodic) - periodic.LastExecution = DateTime.UtcNow; - }); - task.Start(); + task.GetAwaiter().OnCompleted(Finish(startTime, callback)); this.State = WorkerExecutionState.Running; - callback?.Invoke(); + task.Start(); return task; } + + private Action Finish(DateTime startTime, Action? callback = null) => () => + { + DateTime endTime = DateTime.UtcNow; + Log.Info($"Completed {this}\n\t{endTime.Subtract(startTime).TotalMilliseconds} ms"); + this.State = WorkerExecutionState.Completed; + if(this is IPeriodic periodic) + periodic.LastExecution = DateTime.UtcNow; + callback?.Invoke(); + }; protected abstract BaseWorker[] DoWorkInternal(); private BaseWorker[] WaitForDependencies() { Log.Info($"Waiting for {MissingDependencies.Count()} Dependencies {this}:\n\t{string.Join("\n\t", MissingDependencies.Select(d => d.ToString()))}"); - while (CancellationTokenSource.IsCancellationRequested == false && MissingDependencies.Any()) + while (CancellationTokenSource?.IsCancellationRequested == false && MissingDependencies.Any()) { Thread.Sleep(Tranga.Settings.WorkCycleTimeoutMs); }