using API.Schema; using log4net; namespace API.Workers; public abstract class BaseWorker : Identifiable { public BaseWorker[] DependsOn { get; init; } public IEnumerable AllDependencies => DependsOn.Select(d => d.AllDependencies).SelectMany(x => x); public IEnumerable DependenciesAndSelf => AllDependencies.Append(this); public IEnumerable MissingDependencies => DependsOn.Where(d => d.State < WorkerExecutionState.Completed); public bool DependenciesFulfilled => DependsOn.All(d => d.State >= WorkerExecutionState.Completed); internal WorkerExecutionState State { get; set; } private static readonly CancellationTokenSource CancellationTokenSource = new(TimeSpan.FromMinutes(10)); protected ILog Log { get; init; } public void Cancel() { this.State = WorkerExecutionState.Cancelled; CancellationTokenSource.Cancel(); } protected void Fail() => this.State = WorkerExecutionState.Failed; public BaseWorker(IEnumerable? dependsOn = null) { this.DependsOn = dependsOn?.ToArray() ?? []; this.Log = LogManager.GetLogger(GetType()); } public Task DoWork() { this.State = WorkerExecutionState.Waiting; BaseWorker[] missingDependenciesThatNeedStarting = MissingDependencies.Where(d => d.State < WorkerExecutionState.Waiting).ToArray(); if(missingDependenciesThatNeedStarting.Any()) return new Task(() => missingDependenciesThatNeedStarting); if (MissingDependencies.Any()) return new Task(WaitForDependencies); Task task = new (DoWorkInternal, CancellationTokenSource.Token); task.GetAwaiter().OnCompleted(() => this.State = WorkerExecutionState.Completed); task.Start(); this.State = WorkerExecutionState.Running; return task; } protected abstract BaseWorker[] DoWorkInternal(); private BaseWorker[] WaitForDependencies() { while (CancellationTokenSource.IsCancellationRequested == false && MissingDependencies.Any()) { Thread.Sleep(TrangaSettings.workCycleTimeout); } return [this]; } } public enum WorkerExecutionState { Failed = 0, Created = 64, Waiting = 96, Running = 128, Completed = 192, Cancelled = 193 }