mirror of
https://github.com/C9Glax/tranga.git
synced 2025-07-04 01:44:17 +02:00
BaseWorker, BaseWorkerWithContext DoWork, call: Scope setting
TrangaBaseContext Sync return with success state and exception message
This commit is contained in:
@ -5,21 +5,44 @@ namespace API.Workers;
|
||||
|
||||
public abstract class BaseWorker : Identifiable
|
||||
{
|
||||
/// <summary>
|
||||
/// Workers this Worker depends on being completed before running.
|
||||
/// </summary>
|
||||
public BaseWorker[] DependsOn { get; init; }
|
||||
/// <summary>
|
||||
/// Dependencies and dependencies of dependencies. See also <see cref="DependsOn"/>.
|
||||
/// </summary>
|
||||
public IEnumerable<BaseWorker> AllDependencies => DependsOn.Select(d => d.AllDependencies).SelectMany(x => x);
|
||||
/// <summary>
|
||||
/// <see cref="AllDependencies"/> and Self.
|
||||
/// </summary>
|
||||
public IEnumerable<BaseWorker> DependenciesAndSelf => AllDependencies.Append(this);
|
||||
/// <summary>
|
||||
/// <see cref="DependsOn"/> where <see cref="WorkerExecutionState"/> is less than Completed.
|
||||
/// </summary>
|
||||
public IEnumerable<BaseWorker> MissingDependencies => DependsOn.Where(d => d.State < WorkerExecutionState.Completed);
|
||||
public bool DependenciesFulfilled => DependsOn.All(d => d.State >= WorkerExecutionState.Completed);
|
||||
internal WorkerExecutionState State { get; set; }
|
||||
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));
|
||||
protected ILog Log { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Stops worker, and marks as <see cref="WorkerExecutionState"/>.Cancelled
|
||||
/// </summary>
|
||||
public void Cancel()
|
||||
{
|
||||
this.State = WorkerExecutionState.Cancelled;
|
||||
CancellationTokenSource.Cancel();
|
||||
}
|
||||
protected void Fail() => this.State = WorkerExecutionState.Failed;
|
||||
|
||||
/// <summary>
|
||||
/// Stops worker, and marks as <see cref="WorkerExecutionState"/>.Failed
|
||||
/// </summary>
|
||||
protected void Fail()
|
||||
{
|
||||
this.State = WorkerExecutionState.Failed;
|
||||
CancellationTokenSource.Cancel();
|
||||
}
|
||||
|
||||
public BaseWorker(IEnumerable<BaseWorker>? dependsOn = null)
|
||||
{
|
||||
@ -27,6 +50,22 @@ public abstract class BaseWorker : Identifiable
|
||||
this.Log = LogManager.GetLogger(GetType());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets States during worker-run.
|
||||
/// States:
|
||||
/// <list type="bullet">
|
||||
/// <item><see cref="WorkerExecutionState"/>.Waiting when waiting for <see cref="MissingDependencies"/></item>
|
||||
/// <item><see cref="WorkerExecutionState"/>.Running when running</item>
|
||||
/// <item><see cref="WorkerExecutionState"/>.Completed after finished</item>
|
||||
/// </list>
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// <list type="bullet">
|
||||
/// <item>If <see cref="BaseWorker"/> has <see cref="MissingDependencies"/>, missing dependencies.</item>
|
||||
/// <item>If <see cref="MissingDependencies"/> are <see cref="WorkerExecutionState"/>.Running, itself after waiting for dependencies.</item>
|
||||
/// <item>If <see cref="BaseWorker"/> has run, additional <see cref="BaseWorker"/>.</item>
|
||||
/// </list>
|
||||
/// </returns>
|
||||
public Task<BaseWorker[]> DoWork()
|
||||
{
|
||||
this.State = WorkerExecutionState.Waiting;
|
||||
@ -60,9 +99,9 @@ public abstract class BaseWorker : Identifiable
|
||||
public enum WorkerExecutionState
|
||||
{
|
||||
Failed = 0,
|
||||
Cancelled = 32,
|
||||
Created = 64,
|
||||
Waiting = 96,
|
||||
Running = 128,
|
||||
Completed = 192,
|
||||
Cancelled = 193
|
||||
Completed = 192
|
||||
}
|
@ -1,8 +1,18 @@
|
||||
using System.Configuration;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace API.Workers;
|
||||
|
||||
public abstract class BaseWorkerWithContext<T>(IServiceScope scope, IEnumerable<BaseWorker>? dependsOn = null) : BaseWorker(dependsOn) where T : DbContext
|
||||
public abstract class BaseWorkerWithContext<T>(IEnumerable<BaseWorker>? dependsOn = null) : BaseWorker(dependsOn) where T : DbContext
|
||||
{
|
||||
protected T DbContext { get; init; } = scope.ServiceProvider.GetRequiredService<T>();
|
||||
protected T? DbContext = null;
|
||||
public void SetScope(IServiceScope scope) => DbContext = scope.ServiceProvider.GetRequiredService<T>();
|
||||
|
||||
/// <exception cref="ConfigurationErrorsException">Scope has not been set. <see cref="SetScope"/></exception>
|
||||
public new Task<BaseWorker[]> DoWork()
|
||||
{
|
||||
if (DbContext is null)
|
||||
throw new ConfigurationErrorsException("Scope has not been set.");
|
||||
return base.DoWork();
|
||||
}
|
||||
}
|
@ -2,7 +2,7 @@ using API.Schema.MangaContext;
|
||||
|
||||
namespace API.Workers.MaintenanceWorkers;
|
||||
|
||||
public class CleanupMangaCoversWorker(IServiceScope scope, IEnumerable<BaseWorker>? dependsOn = null) : BaseWorkerWithContext<MangaContext>(scope, dependsOn), IPeriodic
|
||||
public class CleanupMangaCoversWorker(IEnumerable<BaseWorker>? dependsOn = null) : BaseWorkerWithContext<MangaContext>(dependsOn), IPeriodic
|
||||
{
|
||||
public DateTime LastExecution { get; set; } = DateTime.UtcNow;
|
||||
public TimeSpan Interval { get; set; } = TimeSpan.FromMinutes(60);
|
||||
|
@ -1,10 +1,8 @@
|
||||
using API.Schema.MangaContext;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace API.Workers;
|
||||
|
||||
public class UpdateChaptersDownloadedWorker(Manga manga, IServiceScope scope, IEnumerable<BaseWorker>? dependsOn = null)
|
||||
: BaseWorkerWithContext<MangaContext>(scope, dependsOn), IPeriodic
|
||||
public class UpdateChaptersDownloadedWorker(Manga manga, IEnumerable<BaseWorker>? dependsOn = null)
|
||||
: BaseWorkerWithContext<MangaContext>(dependsOn), IPeriodic
|
||||
{
|
||||
public DateTime LastExecution { get; set; } = DateTime.UtcNow;
|
||||
public TimeSpan Interval { get; set; } = TimeSpan.FromMinutes(60);
|
||||
@ -15,14 +13,7 @@ public class UpdateChaptersDownloadedWorker(Manga manga, IServiceScope scope, IE
|
||||
mangaChapter.Downloaded = mangaChapter.CheckDownloaded();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
DbContext.SaveChanges();
|
||||
}
|
||||
catch (DbUpdateException e)
|
||||
{
|
||||
Log.Error(e);
|
||||
}
|
||||
DbContext.Sync();
|
||||
return [];
|
||||
}
|
||||
}
|
@ -10,8 +10,8 @@ using static System.IO.UnixFileMode;
|
||||
|
||||
namespace API.Workers;
|
||||
|
||||
public class DownloadChapterFromMangaconnectorWorker(Chapter chapter, IServiceScope scope, IEnumerable<BaseWorker>? dependsOn = null)
|
||||
: BaseWorkerWithContext<MangaContext>(scope, dependsOn)
|
||||
public class DownloadChapterFromMangaconnectorWorker(Chapter chapter, IEnumerable<BaseWorker>? dependsOn = null)
|
||||
: BaseWorkerWithContext<MangaContext>(dependsOn)
|
||||
{
|
||||
protected override BaseWorker[] DoWorkInternal()
|
||||
{
|
||||
@ -89,7 +89,7 @@ public class DownloadChapterFromMangaconnectorWorker(Chapter chapter, IServiceSc
|
||||
Directory.Delete(tempFolder, true); //Cleanup
|
||||
|
||||
chapter.Downloaded = true;
|
||||
DbContext.SaveChanges();
|
||||
DbContext.Sync();
|
||||
|
||||
return [];
|
||||
}
|
||||
|
@ -1,26 +1,20 @@
|
||||
using API.Schema.MangaContext;
|
||||
using API.Schema.MangaContext.MangaConnectors;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace API.Workers;
|
||||
|
||||
public class DownloadCoverFromMangaconnectorWorker(MangaConnectorId<Manga> mcId, IServiceScope scope, IEnumerable<BaseWorker>? dependsOn = null)
|
||||
: BaseWorkerWithContext<MangaContext>(scope, dependsOn)
|
||||
public class DownloadCoverFromMangaconnectorWorker(MangaConnectorId<Manga> mcId, IEnumerable<BaseWorker>? dependsOn = null)
|
||||
: BaseWorkerWithContext<MangaContext>(dependsOn)
|
||||
{
|
||||
public MangaConnectorId<Manga> MangaConnectorId { get; init; } = mcId;
|
||||
protected override BaseWorker[] DoWorkInternal()
|
||||
{
|
||||
MangaConnector mangaConnector = MangaConnectorId.MangaConnector;
|
||||
Manga manga = MangaConnectorId.Obj;
|
||||
try
|
||||
{
|
||||
manga.CoverFileNameInCache = mangaConnector.SaveCoverImageToCache(MangaConnectorId);
|
||||
DbContext.SaveChanges();
|
||||
}
|
||||
catch (DbUpdateException e)
|
||||
{
|
||||
Log.Error(e);
|
||||
}
|
||||
|
||||
manga.CoverFileNameInCache = mangaConnector.SaveCoverImageToCache(MangaConnectorId);
|
||||
|
||||
DbContext.Sync();
|
||||
return [];
|
||||
}
|
||||
}
|
@ -1,11 +1,10 @@
|
||||
using API.Schema.MangaContext;
|
||||
using API.Schema.MangaContext.MangaConnectors;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace API.Workers;
|
||||
|
||||
public class RetrieveMangaChaptersFromMangaconnectorWorker(MangaConnectorId<Manga> mcId, string language, IServiceScope scope, IEnumerable<BaseWorker>? dependsOn = null)
|
||||
: BaseWorkerWithContext<MangaContext>(scope, dependsOn)
|
||||
public class RetrieveMangaChaptersFromMangaconnectorWorker(MangaConnectorId<Manga> mcId, string language, IEnumerable<BaseWorker>? dependsOn = null)
|
||||
: BaseWorkerWithContext<MangaContext>(dependsOn)
|
||||
{
|
||||
public MangaConnectorId<Manga> MangaConnectorId { get; init; } = mcId;
|
||||
protected override BaseWorker[] DoWorkInternal()
|
||||
@ -19,20 +18,13 @@ public class RetrieveMangaChaptersFromMangaconnectorWorker(MangaConnectorId<Mang
|
||||
manga.Chapters.Any(ch => chapter.Item1.Key == ch.Key && ch.Downloaded) == false).ToArray();
|
||||
Log.Info($"{manga.Chapters.Count} existing + {newChapters.Length} new chapters.");
|
||||
|
||||
try
|
||||
foreach ((Chapter chapter, MangaConnectorId<Chapter> mcId) newChapter in newChapters)
|
||||
{
|
||||
foreach ((Chapter chapter, MangaConnectorId<Chapter> mcId) newChapter in newChapters)
|
||||
{
|
||||
manga.Chapters.Add(newChapter.chapter);
|
||||
DbContext.MangaConnectorToChapter.Add(newChapter.mcId);
|
||||
}
|
||||
manga.Chapters.Add(newChapter.chapter);
|
||||
DbContext.MangaConnectorToChapter.Add(newChapter.mcId);
|
||||
}
|
||||
|
||||
DbContext.SaveChanges();
|
||||
}
|
||||
catch (DbUpdateException e)
|
||||
{
|
||||
Log.Error(e);
|
||||
}
|
||||
DbContext.Sync();
|
||||
|
||||
return [];
|
||||
}
|
||||
|
@ -1,24 +1,17 @@
|
||||
using API.Schema.MangaContext;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace API.Workers;
|
||||
|
||||
public class MoveMangaLibraryWorker(Manga manga, FileLibrary toLibrary, IServiceScope scope, IEnumerable<BaseWorker>? dependsOn = null)
|
||||
: BaseWorkerWithContext<MangaContext>(scope, dependsOn)
|
||||
: BaseWorkerWithContext<MangaContext>(dependsOn)
|
||||
{
|
||||
protected override BaseWorker[] DoWorkInternal()
|
||||
{
|
||||
Dictionary<Chapter, string> oldPath = manga.Chapters.ToDictionary(c => c, c => c.FullArchiveFilePath);
|
||||
manga.Library = toLibrary;
|
||||
try
|
||||
{
|
||||
DbContext.SaveChanges();
|
||||
}
|
||||
catch (DbUpdateException e)
|
||||
{
|
||||
Log.Error(e);
|
||||
|
||||
if (DbContext.Sync().Result is { success: false })
|
||||
return [];
|
||||
}
|
||||
|
||||
return manga.Chapters.Select(c => new MoveFileOrFolderWorker(c.FullArchiveFilePath, oldPath[c])).ToArray<BaseWorker>();
|
||||
}
|
||||
|
@ -2,8 +2,8 @@ using API.Schema.NotificationsContext;
|
||||
|
||||
namespace API.Workers;
|
||||
|
||||
public class SendNotificationsWorker(IServiceScope scope, IEnumerable<BaseWorker>? dependsOn = null)
|
||||
: BaseWorkerWithContext<NotificationsContext>(scope, dependsOn), IPeriodic
|
||||
public class SendNotificationsWorker(IEnumerable<BaseWorker>? dependsOn = null)
|
||||
: BaseWorkerWithContext<NotificationsContext>(dependsOn), IPeriodic
|
||||
{
|
||||
public DateTime LastExecution { get; set; } = DateTime.UtcNow;
|
||||
public TimeSpan Interval { get; set; } = TimeSpan.FromMinutes(1);
|
||||
|
Reference in New Issue
Block a user