mirror of
https://github.com/C9Glax/tranga.git
synced 2025-07-03 09:24:16 +02:00
BaseWorker, BaseWorkerWithContext DoWork, call: Scope setting
TrangaBaseContext Sync return with success state and exception message
This commit is contained in:
@ -63,8 +63,8 @@ public class FileLibraryController(IServiceScope scope) : Controller
|
||||
//TODO Path check
|
||||
library.BasePath = newBasePath;
|
||||
|
||||
if(context.Sync().Result is { } errorMessage)
|
||||
return StatusCode(Status500InternalServerError, errorMessage);
|
||||
if(context.Sync().Result is { success: false } result)
|
||||
return StatusCode(Status500InternalServerError, result.exceptionMessage);
|
||||
return Ok();
|
||||
}
|
||||
|
||||
@ -90,8 +90,8 @@ public class FileLibraryController(IServiceScope scope) : Controller
|
||||
//TODO Name check
|
||||
library.LibraryName = newName;
|
||||
|
||||
if(context.Sync().Result is { } errorMessage)
|
||||
return StatusCode(Status500InternalServerError, errorMessage);
|
||||
if(context.Sync().Result is { success: false } result)
|
||||
return StatusCode(Status500InternalServerError, result.exceptionMessage);
|
||||
return Ok();
|
||||
}
|
||||
|
||||
@ -111,8 +111,8 @@ public class FileLibraryController(IServiceScope scope) : Controller
|
||||
//TODO Parameter check
|
||||
context.FileLibraries.Add(library);
|
||||
|
||||
if(context.Sync().Result is { } errorMessage)
|
||||
return StatusCode(Status500InternalServerError, errorMessage);
|
||||
if(context.Sync().Result is { success: false } result)
|
||||
return StatusCode(Status500InternalServerError, result.exceptionMessage);
|
||||
return Created();
|
||||
}
|
||||
|
||||
@ -134,8 +134,8 @@ public class FileLibraryController(IServiceScope scope) : Controller
|
||||
|
||||
context.FileLibraries.Remove(library);
|
||||
|
||||
if(context.Sync().Result is { } errorMessage)
|
||||
return StatusCode(Status500InternalServerError, errorMessage);
|
||||
if(context.Sync().Result is { success: false } result)
|
||||
return StatusCode(Status500InternalServerError, result.exceptionMessage);
|
||||
return Ok();
|
||||
}
|
||||
}
|
@ -60,8 +60,8 @@ public class LibraryConnectorController(IServiceScope scope) : Controller
|
||||
|
||||
context.LibraryConnectors.Add(libraryConnector);
|
||||
|
||||
if(context.Sync().Result is { } errorMessage)
|
||||
return StatusCode(Status500InternalServerError, errorMessage);
|
||||
if(context.Sync().Result is { success: false } result)
|
||||
return StatusCode(Status500InternalServerError, result.exceptionMessage);
|
||||
return Created();
|
||||
}
|
||||
|
||||
@ -84,8 +84,8 @@ public class LibraryConnectorController(IServiceScope scope) : Controller
|
||||
|
||||
context.LibraryConnectors.Remove(connector);
|
||||
|
||||
if(context.Sync().Result is { } errorMessage)
|
||||
return StatusCode(Status500InternalServerError, errorMessage);
|
||||
if(context.Sync().Result is { success: false } result)
|
||||
return StatusCode(Status500InternalServerError, result.exceptionMessage);
|
||||
return Ok();
|
||||
}
|
||||
}
|
@ -88,8 +88,8 @@ public class MangaConnectorController(IServiceScope scope) : Controller
|
||||
|
||||
connector.Enabled = Enabled;
|
||||
|
||||
if(context.Sync().Result is { } errorMessage)
|
||||
return StatusCode(Status500InternalServerError, errorMessage);
|
||||
if(context.Sync().Result is { success: false } result)
|
||||
return StatusCode(Status500InternalServerError, result.exceptionMessage);
|
||||
return Accepted();
|
||||
}
|
||||
}
|
@ -81,8 +81,8 @@ public class MangaController(IServiceScope scope) : Controller
|
||||
|
||||
context.Mangas.Remove(manga);
|
||||
|
||||
if(context.Sync().Result is { } errorMessage)
|
||||
return StatusCode(Status500InternalServerError, errorMessage);
|
||||
if(context.Sync().Result is { success: false } result)
|
||||
return StatusCode(Status500InternalServerError, result.exceptionMessage);
|
||||
return Ok();
|
||||
}
|
||||
|
||||
@ -329,8 +329,8 @@ public class MangaController(IServiceScope scope) : Controller
|
||||
return NotFound();
|
||||
|
||||
manga.IgnoreChaptersBefore = chapterThreshold;
|
||||
if(context.Sync().Result is { } errorMessage)
|
||||
return StatusCode(Status500InternalServerError, errorMessage);
|
||||
if(context.Sync().Result is { success: false } result)
|
||||
return StatusCode(Status500InternalServerError, result.exceptionMessage);
|
||||
|
||||
return Accepted();
|
||||
}
|
||||
@ -354,7 +354,7 @@ public class MangaController(IServiceScope scope) : Controller
|
||||
return NotFound(nameof(LibraryId));
|
||||
|
||||
MoveMangaLibraryWorker moveLibrary = new(manga, library, scope);
|
||||
UpdateChaptersDownloadedWorker updateDownloadedFiles = new(manga, scope, [moveLibrary]);
|
||||
UpdateChaptersDownloadedWorker updateDownloadedFiles = new(manga, [moveLibrary]);
|
||||
|
||||
Tranga.AddWorkers([moveLibrary, updateDownloadedFiles]);
|
||||
|
||||
|
@ -119,8 +119,8 @@ public class MetadataFetcherController(IServiceScope scope) : Controller
|
||||
|
||||
context.Remove(entry);
|
||||
|
||||
if(context.Sync().Result is { } errorMessage)
|
||||
return StatusCode(Status500InternalServerError, errorMessage);
|
||||
if(context.Sync().Result is { success: false } result)
|
||||
return StatusCode(Status500InternalServerError, result.exceptionMessage);
|
||||
return Ok();
|
||||
}
|
||||
}
|
@ -62,8 +62,8 @@ public class NotificationConnectorController(IServiceScope scope) : Controller
|
||||
|
||||
context.NotificationConnectors.Add(notificationConnector);
|
||||
|
||||
if(context.Sync().Result is { } errorMessage)
|
||||
return StatusCode(Status500InternalServerError, errorMessage);
|
||||
if(context.Sync().Result is { success: false } result)
|
||||
return StatusCode(Status500InternalServerError, result.exceptionMessage);
|
||||
return Created();
|
||||
}
|
||||
|
||||
@ -156,8 +156,8 @@ public class NotificationConnectorController(IServiceScope scope) : Controller
|
||||
|
||||
context.NotificationConnectors.Remove(connector);
|
||||
|
||||
if(context.Sync().Result is { } errorMessage)
|
||||
return StatusCode(Status500InternalServerError, errorMessage);
|
||||
if(context.Sync().Result is { success: false } result)
|
||||
return StatusCode(Status500InternalServerError, result.exceptionMessage);
|
||||
return Created();
|
||||
}
|
||||
}
|
@ -96,7 +96,7 @@ public class SearchController(IServiceScope scope) : Controller
|
||||
if(context.MangaConnectorToManga.Find(addMcId.Key) is null)
|
||||
context.MangaConnectorToManga.Add(mcId);
|
||||
|
||||
if (context.Sync().Result is not null)
|
||||
if (context.Sync().Result is { success: false } )
|
||||
return null;
|
||||
return manga;
|
||||
}
|
||||
|
@ -1,10 +1,8 @@
|
||||
using API.APIEndpointRecords;
|
||||
using API.Schema.MangaContext;
|
||||
using API.Workers;
|
||||
using Asp.Versioning;
|
||||
using log4net;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
using static Microsoft.AspNetCore.Http.StatusCodes;
|
||||
// ReSharper disable InconsistentNaming
|
||||
|
||||
@ -129,7 +127,7 @@ public class WorkerController(ILog Log) : Controller
|
||||
if (worker.State >= WorkerExecutionState.Waiting)
|
||||
return StatusCode(Status412PreconditionFailed, "Already running");
|
||||
|
||||
Tranga.StartWorker(worker);
|
||||
Tranga.MarkWorkerForStart(worker);
|
||||
return Ok();
|
||||
}
|
||||
|
||||
|
@ -22,17 +22,17 @@ public abstract class TrangaBaseContext<T> : DbContext where T : DbContext
|
||||
}, Array.Empty<string>(), LogLevel.Warning, DbContextLoggerOptions.Level | DbContextLoggerOptions.Category | DbContextLoggerOptions.UtcTime);
|
||||
}
|
||||
|
||||
internal async Task<string?> Sync()
|
||||
internal async Task<(bool success, string? exceptionMessage)> Sync()
|
||||
{
|
||||
try
|
||||
{
|
||||
await this.SaveChangesAsync();
|
||||
return null;
|
||||
return (true, null);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(null, e);
|
||||
return e.Message;
|
||||
return (false, e.Message);
|
||||
}
|
||||
}
|
||||
}
|
@ -2,6 +2,7 @@
|
||||
using API.Workers;
|
||||
using log4net;
|
||||
using log4net.Config;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace API;
|
||||
|
||||
@ -54,6 +55,7 @@ public static class Tranga
|
||||
|
||||
private static readonly Dictionary<BaseWorker, Thread> RunningWorkers = new();
|
||||
public static BaseWorker[] GetRunningWorkers() => RunningWorkers.Keys.ToArray();
|
||||
private static readonly HashSet<BaseWorker> StartWorkers = new();
|
||||
private static void WorkerStarter(object? serviceProviderObj)
|
||||
{
|
||||
Log.Info("WorkerStarter Thread running.");
|
||||
@ -66,19 +68,26 @@ public static class Tranga
|
||||
|
||||
while (true)
|
||||
{
|
||||
using IServiceScope scope = serviceProvider.CreateScope();
|
||||
|
||||
foreach (BaseWorker startWorker in StartWorkers)
|
||||
{
|
||||
IServiceScope scope = serviceProvider.CreateScope();
|
||||
StartWorker(startWorker, scope);
|
||||
}
|
||||
Thread.Sleep(TrangaSettings.workCycleTimeout);
|
||||
}
|
||||
}
|
||||
|
||||
internal static void StartWorker(BaseWorker worker)
|
||||
internal static void MarkWorkerForStart(BaseWorker worker) => StartWorkers.Add(worker);
|
||||
|
||||
private static void StartWorker(BaseWorker worker, IServiceScope scope)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
if(worker is BaseWorkerWithContext<DbContext> w)
|
||||
w.SetScope(scope);
|
||||
worker.DoWork();
|
||||
}
|
||||
|
||||
internal static void StopWorker(BaseWorker worker)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
worker.Cancel();
|
||||
}
|
||||
}
|
@ -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