Implemented Queue, so that taskManager is not held up with other Connector-tasks.

Tasks are now executed in another Thread.
Replaced TrangaTask.isBeingExecuted bool with 3-states: Waiting, Enqueued, Running
Added Queue size to CLI output.
This commit is contained in:
glax 2023-05-20 14:50:48 +02:00
parent 58de0115d6
commit 430ee2301f
4 changed files with 47 additions and 20 deletions

View File

@ -129,7 +129,7 @@ public static class Tranga_Cli
menu = 0; menu = 0;
break; break;
case 6: case 6:
PrintTasks(taskManager.GetAllTasks().Where(eTask => eTask.isBeingExecuted).ToArray()); PrintTasks(taskManager.GetAllTasks().Where(eTask => eTask.state == TrangaTask.ExecutionState.Running).ToArray());
Console.WriteLine("Press any key."); Console.WriteLine("Press any key.");
Console.ReadKey(); Console.ReadKey();
menu = 0; menu = 0;
@ -167,7 +167,7 @@ public static class Tranga_Cli
} }
} }
if (taskManager.GetAllTasks().Any(task => task.isBeingExecuted)) if (taskManager.GetAllTasks().Any(task => task.state == TrangaTask.ExecutionState.Running))
{ {
Console.WriteLine("Force quit (Even with running tasks?) y/N"); Console.WriteLine("Force quit (Even with running tasks?) y/N");
selection = Console.ReadKey().Key; selection = Console.ReadKey().Key;
@ -182,9 +182,11 @@ public static class Tranga_Cli
private static ConsoleKey Menu(TaskManager taskManager, string folderPath) private static ConsoleKey Menu(TaskManager taskManager, string folderPath)
{ {
int taskCount = taskManager.GetAllTasks().Length; int taskCount = taskManager.GetAllTasks().Length;
int taskRunningCount = taskManager.GetAllTasks().Count(task => task.isBeingExecuted); int taskRunningCount = taskManager.GetAllTasks().Count(task => task.state == TrangaTask.ExecutionState.Running);
int taskEnqueuedCount =
taskManager.GetAllTasks().Count(task => task.state == TrangaTask.ExecutionState.Enqueued);
Console.Clear(); Console.Clear();
Console.WriteLine($"Download Folder: {folderPath} Tasks (Running/Total): {taskRunningCount}/{taskCount}"); Console.WriteLine($"Download Folder: {folderPath} Tasks (Running/Queue/Total): {taskRunningCount}/{taskEnqueuedCount}/{taskCount}");
Console.WriteLine("U: Update this Screen"); Console.WriteLine("U: Update this Screen");
Console.WriteLine("L: List tasks"); Console.WriteLine("L: List tasks");
Console.WriteLine("C: Create Task"); Console.WriteLine("C: Create Task");
@ -201,10 +203,11 @@ public static class Tranga_Cli
private static void PrintTasks(TrangaTask[] tasks) private static void PrintTasks(TrangaTask[] tasks)
{ {
int taskCount = tasks.Length; int taskCount = tasks.Length;
int taskRunningCount = tasks.Count(task => task.isBeingExecuted); int taskRunningCount = tasks.Count(task => task.state == TrangaTask.ExecutionState.Running);
int taskEnqueuedCount = tasks.Count(task => task.state == TrangaTask.ExecutionState.Enqueued);
Console.Clear(); Console.Clear();
int tIndex = 0; int tIndex = 0;
Console.WriteLine($"Tasks (Running/Total): {taskRunningCount}/{taskCount}"); Console.WriteLine($"Tasks (Running/Queue/Total): {taskRunningCount}/{taskEnqueuedCount}/{taskCount}");
foreach(TrangaTask trangaTask in tasks) foreach(TrangaTask trangaTask in tasks)
Console.WriteLine($"{tIndex++:000}: {trangaTask}"); Console.WriteLine($"{tIndex++:000}: {trangaTask}");
} }

View File

@ -16,15 +16,14 @@ public static class TaskExecutor
/// <exception cref="ArgumentException">Is thrown when there is no Connector available with the name of the TrangaTask.connectorName</exception> /// <exception cref="ArgumentException">Is thrown when there is no Connector available with the name of the TrangaTask.connectorName</exception>
public static void Execute(TaskManager taskManager, TrangaTask trangaTask, Dictionary<Publication, List<Chapter>> chapterCollection) public static void Execute(TaskManager taskManager, TrangaTask trangaTask, Dictionary<Publication, List<Chapter>> chapterCollection)
{ {
if (trangaTask.state == TrangaTask.ExecutionState.Running)
return;
trangaTask.state = TrangaTask.ExecutionState.Running;
Connector? connector = null; Connector? connector = null;
if (trangaTask.task != TrangaTask.Task.UpdateKomgaLibrary) if (trangaTask.task != TrangaTask.Task.UpdateKomgaLibrary)
connector = taskManager.GetConnector(trangaTask.connectorName!); connector = taskManager.GetConnector(trangaTask.connectorName!);
if (trangaTask.isBeingExecuted)
return;
trangaTask.isBeingExecuted = true;
trangaTask.lastExecuted = DateTime.Now;
//Call appropriate Method based on TrangaTask.Task //Call appropriate Method based on TrangaTask.Task
switch (trangaTask.task) switch (trangaTask.task)
{ {
@ -42,7 +41,8 @@ public static class TaskExecutor
break; break;
} }
trangaTask.isBeingExecuted = false; trangaTask.state = TrangaTask.ExecutionState.Waiting;
trangaTask.lastExecuted = DateTime.Now;
} }
/// <summary> /// <summary>

View File

@ -13,6 +13,7 @@ public class TaskManager
private readonly HashSet<TrangaTask> _allTasks; private readonly HashSet<TrangaTask> _allTasks;
private bool _continueRunning = true; private bool _continueRunning = true;
private readonly Connector[] _connectors; private readonly Connector[] _connectors;
private Dictionary<Connector, List<TrangaTask>> tasksToExecute = new();
private string downloadLocation { get; } private string downloadLocation { get; }
public Komga? komga { get; private set; } public Komga? komga { get; private set; }
@ -26,6 +27,8 @@ public class TaskManager
if (komgaBaseUrl != null && komgaUsername != null && komgaPassword != null) if (komgaBaseUrl != null && komgaUsername != null && komgaPassword != null)
this.komga = new Komga(komgaBaseUrl, komgaUsername, komgaPassword); this.komga = new Komga(komgaBaseUrl, komgaUsername, komgaPassword);
this._connectors = new Connector[]{ new MangaDex(folderPath) }; this._connectors = new Connector[]{ new MangaDex(folderPath) };
foreach(Connector cConnector in this._connectors)
tasksToExecute.Add(cConnector, new List<TrangaTask>());
_allTasks = new HashSet<TrangaTask>(); _allTasks = new HashSet<TrangaTask>();
Thread taskChecker = new(TaskCheckerThread); Thread taskChecker = new(TaskCheckerThread);
@ -35,6 +38,8 @@ public class TaskManager
public TaskManager(SettingsData settings) public TaskManager(SettingsData settings)
{ {
this._connectors = new Connector[]{ new MangaDex(settings.downloadLocation) }; this._connectors = new Connector[]{ new MangaDex(settings.downloadLocation) };
foreach(Connector cConnector in this._connectors)
tasksToExecute.Add(cConnector, new List<TrangaTask>());
this.downloadLocation = settings.downloadLocation; this.downloadLocation = settings.downloadLocation;
this.komga = settings.komga; this.komga = settings.komga;
_allTasks = settings.allTasks; _allTasks = settings.allTasks;
@ -46,10 +51,22 @@ public class TaskManager
{ {
while (_continueRunning) while (_continueRunning)
{ {
foreach (TrangaTask task in _allTasks) foreach (KeyValuePair<Connector, List<TrangaTask>> connectorTaskQueue in tasksToExecute)
{ {
if(task.ShouldExecute()) connectorTaskQueue.Value.RemoveAll(task => task.state == TrangaTask.ExecutionState.Waiting);
TaskExecutor.Execute(this, task, this._chapterCollection); //TODO Might crash here, when adding new Task while another Task is running. Check later if (connectorTaskQueue.Value.Count > 0 && !connectorTaskQueue.Value.All(task => task.state is TrangaTask.ExecutionState.Running or TrangaTask.ExecutionState.Waiting))
ExecuteTaskNow(connectorTaskQueue.Value.First());
}
foreach (TrangaTask task in _allTasks.Where(aTask => aTask.ShouldExecute()))
{
task.state = TrangaTask.ExecutionState.Enqueued;
if(task.connectorName is null)
ExecuteTaskNow(task);
else
{
tasksToExecute[GetConnector(task.connectorName!)].Add(task);
}
} }
Thread.Sleep(1000); Thread.Sleep(1000);
} }
@ -173,10 +190,10 @@ public class TaskManager
ExportData(Directory.GetCurrentDirectory()); ExportData(Directory.GetCurrentDirectory());
if(force) if(force)
Environment.Exit(_allTasks.Count(task => task.isBeingExecuted)); Environment.Exit(_allTasks.Count(task => task.state is TrangaTask.ExecutionState.Enqueued or TrangaTask.ExecutionState.Running));
//Wait for tasks to finish //Wait for tasks to finish
while(_allTasks.Any(task => task.isBeingExecuted)) while(_allTasks.Any(task => task.state is TrangaTask.ExecutionState.Running or TrangaTask.ExecutionState.Enqueued))
Thread.Sleep(10); Thread.Sleep(10);
Environment.Exit(0); Environment.Exit(0);
} }

View File

@ -15,7 +15,14 @@ public class TrangaTask
public Task task { get; } public Task task { get; }
public Publication? publication { get; } public Publication? publication { get; }
public string language { get; } public string language { get; }
[JsonIgnore]public bool isBeingExecuted { get; set; } [JsonIgnore]public ExecutionState state { get; set; }
public enum ExecutionState
{
Waiting,
Enqueued,
Running
};
public TrangaTask(Task task, string? connectorName, Publication? publication, TimeSpan reoccurrence, string language = "") public TrangaTask(Task task, string? connectorName, Publication? publication, TimeSpan reoccurrence, string language = "")
{ {
@ -36,7 +43,7 @@ public class TrangaTask
/// <returns>True if elapsed time since last execution is greater than set interval</returns> /// <returns>True if elapsed time since last execution is greater than set interval</returns>
public bool ShouldExecute() public bool ShouldExecute()
{ {
return DateTime.Now.Subtract(this.lastExecuted) > reoccurrence; return DateTime.Now.Subtract(this.lastExecuted) > reoccurrence && state is ExecutionState.Waiting;
} }
public enum Task public enum Task
@ -49,6 +56,6 @@ public class TrangaTask
public override string ToString() public override string ToString()
{ {
return $"{task}\t{lastExecuted}\t{reoccurrence}\t{(isBeingExecuted ? "running" : "waiting")}\t{connectorName}\t{publication?.sortName}"; return $"{task}\t{lastExecuted}\t{reoccurrence}\t{state}\t{connectorName}\t{publication?.sortName}";
} }
} }