Attach Entities to Jobs

This commit is contained in:
Glax 2025-05-15 15:13:53 +02:00
parent 694b88d200
commit 475a29b10d
23 changed files with 132 additions and 57 deletions

View File

@ -1,5 +1,6 @@
using API.APIEndpointRecords; using API.APIEndpointRecords;
using API.Schema; using API.Schema;
using API.Schema.Contexts;
using API.Schema.Jobs; using API.Schema.Jobs;
using Asp.Versioning; using Asp.Versioning;
using log4net; using log4net;

View File

@ -1,4 +1,5 @@
using API.Schema; using API.Schema;
using API.Schema.Contexts;
using API.Schema.LibraryConnectors; using API.Schema.LibraryConnectors;
using Asp.Versioning; using Asp.Versioning;
using log4net; using log4net;
@ -10,7 +11,7 @@ namespace API.Controllers;
[ApiVersion(2)] [ApiVersion(2)]
[ApiController] [ApiController]
[Route("v{v:apiVersion}/[controller]")] [Route("v{v:apiVersion}/[controller]")]
public class LibraryConnectorController(PgsqlContext context, ILog Log) : Controller public class LibraryConnectorController(LibraryContext context, ILog Log) : Controller
{ {
/// <summary> /// <summary>
/// Gets all configured ToLibrary-Connectors /// Gets all configured ToLibrary-Connectors

View File

@ -1,5 +1,6 @@
using API.APIEndpointRecords; using API.APIEndpointRecords;
using API.Schema; using API.Schema;
using API.Schema.Contexts;
using Asp.Versioning; using Asp.Versioning;
using log4net; using log4net;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;

View File

@ -1,4 +1,4 @@
using API.Schema; using API.Schema.Contexts;
using API.Schema.MangaConnectors; using API.Schema.MangaConnectors;
using Asp.Versioning; using Asp.Versioning;
using log4net; using log4net;

View File

@ -1,4 +1,5 @@
using API.Schema; using API.Schema;
using API.Schema.Contexts;
using API.Schema.Jobs; using API.Schema.Jobs;
using Asp.Versioning; using Asp.Versioning;
using log4net; using log4net;

View File

@ -1,6 +1,6 @@
using System.Text; using System.Text;
using API.APIEndpointRecords; using API.APIEndpointRecords;
using API.Schema; using API.Schema.Contexts;
using API.Schema.NotificationConnectors; using API.Schema.NotificationConnectors;
using Asp.Versioning; using Asp.Versioning;
using log4net; using log4net;
@ -13,7 +13,7 @@ namespace API.Controllers;
[ApiController] [ApiController]
[Produces("application/json")] [Produces("application/json")]
[Route("v{v:apiVersion}/[controller]")] [Route("v{v:apiVersion}/[controller]")]
public class NotificationConnectorController(PgsqlContext context, ILog Log) : Controller public class NotificationConnectorController(NotificationsContext context, ILog Log) : Controller
{ {
/// <summary> /// <summary>
/// Gets all configured Notification-Connectors /// Gets all configured Notification-Connectors

View File

@ -1,4 +1,5 @@
using API.Schema; using API.Schema;
using API.Schema.Contexts;
using Asp.Versioning; using Asp.Versioning;
using log4net; using log4net;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;

View File

@ -1,4 +1,5 @@
using API.Schema; using API.Schema;
using API.Schema.Contexts;
using API.Schema.Jobs; using API.Schema.Jobs;
using API.Schema.MangaConnectors; using API.Schema.MangaConnectors;
using Asp.Versioning; using Asp.Versioning;

View File

@ -1,5 +1,6 @@
using API.MangaDownloadClients; using API.MangaDownloadClients;
using API.Schema; using API.Schema;
using API.Schema.Contexts;
using API.Schema.Jobs; using API.Schema.Jobs;
using Asp.Versioning; using Asp.Versioning;
using log4net; using log4net;

View File

@ -1,7 +1,7 @@
using System.Reflection; using System.Reflection;
using System.Text.Json.Serialization;
using API; using API;
using API.Schema; using API.Schema;
using API.Schema.Contexts;
using API.Schema.Jobs; using API.Schema.Jobs;
using API.Schema.MangaConnectors; using API.Schema.MangaConnectors;
using Asp.Versioning; using Asp.Versioning;
@ -55,11 +55,17 @@ builder.Services.AddSwaggerGen(opt =>
}); });
builder.Services.ConfigureOptions<NamedSwaggerGenOptions>(); builder.Services.ConfigureOptions<NamedSwaggerGenOptions>();
string ConnectionString = $"Host={Environment.GetEnvironmentVariable("POSTGRES_HOST") ?? "localhost:5432"}; " +
$"Database={Environment.GetEnvironmentVariable("POSTGRES_DB") ?? "postgres"}; " +
$"Username={Environment.GetEnvironmentVariable("POSTGRES_USER") ?? "postgres"}; " +
$"Password={Environment.GetEnvironmentVariable("POSTGRES_PASSWORD") ?? "postgres"}";
builder.Services.AddDbContext<PgsqlContext>(options => builder.Services.AddDbContext<PgsqlContext>(options =>
options.UseNpgsql($"Host={Environment.GetEnvironmentVariable("POSTGRES_HOST")??"localhost:5432"}; " + options.UseNpgsql(ConnectionString));
$"Database={Environment.GetEnvironmentVariable("POSTGRES_DB")??"postgres"}; " + builder.Services.AddDbContext<NotificationsContext>(options =>
$"Username={Environment.GetEnvironmentVariable("POSTGRES_USER")??"postgres"}; " + options.UseNpgsql(ConnectionString));
$"Password={Environment.GetEnvironmentVariable("POSTGRES_PASSWORD")??"postgres"}")); builder.Services.AddDbContext<LibraryContext>(options =>
options.UseNpgsql(ConnectionString));
builder.Services.AddControllers(options => builder.Services.AddControllers(options =>
{ {
@ -99,30 +105,42 @@ app.UseHttpsRedirection();
app.UseMiddleware<RequestTimeMiddleware>(); app.UseMiddleware<RequestTimeMiddleware>();
using (var scope = app.Services.CreateScope()) using (IServiceScope scope = app.Services.CreateScope())
{ {
var db = scope.ServiceProvider.GetRequiredService<PgsqlContext>(); PgsqlContext context = scope.ServiceProvider.GetRequiredService<PgsqlContext>();
db.Database.Migrate(); context.Database.Migrate();
}
using (var scope = app.Services.CreateScope())
{
PgsqlContext context = scope.ServiceProvider.GetService<PgsqlContext>()!;
MangaConnector[] connectors = MangaConnector[] connectors =
[ [
new MangaDex(), new MangaDex(),
new Global(scope.ServiceProvider.GetService<PgsqlContext>()!) new Global(scope.ServiceProvider.GetService<PgsqlContext>()!)
]; ];
MangaConnector[] newConnectors = connectors.Where(c => !context.MangaConnectors.Contains(c)).ToArray(); MangaConnector[] newConnectors = connectors.Where(c => !context.MangaConnectors.Contains(c)).ToArray();
context.MangaConnectors.AddRange(newConnectors); context.MangaConnectors.AddRange(newConnectors);
context.Jobs.AddRange(context.Mangas.AsEnumerable().Select(m => new UpdateFilesDownloadedJob(m, 0)));
context.Jobs.RemoveRange(context.Jobs.Where(j => j.state == JobState.Completed && j.RecurrenceMs < 1));
if (!context.LocalLibraries.Any()) if (!context.LocalLibraries.Any())
context.LocalLibraries.Add(new LocalLibrary(TrangaSettings.downloadLocation, "Default ToLibrary")); context.LocalLibraries.Add(new LocalLibrary(TrangaSettings.downloadLocation, "Default Library"));
context.Jobs.AddRange(context.Jobs.Where(j => j.JobType == JobType.DownloadAvailableChaptersJob)
.AsEnumerable()
.Select(dacj =>
{
DownloadAvailableChaptersJob? j = dacj as DownloadAvailableChaptersJob;
return new UpdateFilesDownloadedJob(j!.Manga, 0);
}));
context.Jobs.RemoveRange(context.Jobs.Where(j => j.state == JobState.Completed && j.RecurrenceMs < 1));
foreach (Job job in context.Jobs.Where(j => j.state == JobState.Running))
{
job.state = JobState.FirstExecution;
job.LastExecution = DateTime.UnixEpoch;
}
context.SaveChanges();
}
using (IServiceScope scope = app.Services.CreateScope())
{
NotificationsContext context = scope.ServiceProvider.GetRequiredService<NotificationsContext>();
context.Database.Migrate();
string[] emojis = { "(•‿•)", "(づ \u25d5‿\u25d5 )づ", "( \u02d8\u25bd\u02d8)っ\u2668", "=\uff3e\u25cf \u22cf \u25cf\uff3e=", "(ΦωΦ)", "(\u272a\u3268\u272a)", "( ノ・o・ )ノ", "(〜^\u2207^ )〜", "~(\u2267ω\u2266)~","૮ \u00b4• ﻌ \u00b4• ა", "(\u02c3ᆺ\u02c2)", "(=\ud83d\udf66 \u0f1d \ud83d\udf66=)"}; string[] emojis = { "(•‿•)", "(づ \u25d5‿\u25d5 )づ", "( \u02d8\u25bd\u02d8)っ\u2668", "=\uff3e\u25cf \u22cf \u25cf\uff3e=", "(ΦωΦ)", "(\u272a\u3268\u272a)", "( ノ・o・ )ノ", "(〜^\u2207^ )〜", "~(\u2267ω\u2266)~","૮ \u00b4• ﻌ \u00b4• ა", "(\u02c3ᆺ\u02c2)", "(=\ud83d\udf66 \u0f1d \ud83d\udf66=)"};
context.Notifications.Add(new Notification("Tranga Started", emojis[Random.Shared.Next(0, emojis.Length - 1)], NotificationUrgency.High)); context.Notifications.Add(new Notification("Tranga Started", emojis[Random.Shared.Next(0, emojis.Length - 1)], NotificationUrgency.High));

View File

@ -0,0 +1,18 @@
using API.Schema.LibraryConnectors;
using Microsoft.EntityFrameworkCore;
namespace API.Schema.Contexts;
public class LibraryContext(DbContextOptions<LibraryContext> options) : DbContext(options)
{
public DbSet<LibraryConnector> LibraryConnectors { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
//LibraryConnector Types
modelBuilder.Entity<LibraryConnector>()
.HasDiscriminator(l => l.LibraryType)
.HasValue<Komga>(LibraryType.Komga)
.HasValue<Kavita>(LibraryType.Kavita);
}
}

View File

@ -0,0 +1,10 @@
using API.Schema.NotificationConnectors;
using Microsoft.EntityFrameworkCore;
namespace API.Schema.Contexts;
public class NotificationsContext(DbContextOptions<NotificationsContext> options) : DbContext(options)
{
public DbSet<NotificationConnector> NotificationConnectors { get; set; }
public DbSet<Notification> Notifications { get; set; }
}

View File

@ -1,10 +1,9 @@
using API.Schema.Jobs; using API.Schema.Jobs;
using API.Schema.LibraryConnectors; using API.Schema.LibraryConnectors;
using API.Schema.MangaConnectors; using API.Schema.MangaConnectors;
using API.Schema.NotificationConnectors;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
namespace API.Schema; namespace API.Schema.Contexts;
public class PgsqlContext(DbContextOptions<PgsqlContext> options) : DbContext(options) public class PgsqlContext(DbContextOptions<PgsqlContext> options) : DbContext(options)
{ {
@ -15,9 +14,6 @@ public class PgsqlContext(DbContextOptions<PgsqlContext> options) : DbContext(op
public DbSet<Chapter> Chapters { get; set; } public DbSet<Chapter> Chapters { get; set; }
public DbSet<Author> Authors { get; set; } public DbSet<Author> Authors { get; set; }
public DbSet<MangaTag> Tags { get; set; } public DbSet<MangaTag> Tags { get; set; }
public DbSet<LibraryConnector> LibraryConnectors { get; set; }
public DbSet<NotificationConnector> NotificationConnectors { get; set; }
public DbSet<Notification> Notifications { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder) protected override void OnModelCreating(ModelBuilder modelBuilder)
{ {
@ -109,7 +105,7 @@ public class PgsqlContext(DbContextOptions<PgsqlContext> options) : DbContext(op
.HasMany<Job>(root => root.DependsOnJobs) .HasMany<Job>(root => root.DependsOnJobs)
.WithMany(); .WithMany();
modelBuilder.Entity<Job>() modelBuilder.Entity<Job>()
.Navigation(root => root.DependsOnJobs) .Navigation(j => j.DependsOnJobs)
.AutoInclude(false); .AutoInclude(false);
//MangaConnector Types //MangaConnector Types
@ -138,14 +134,23 @@ public class PgsqlContext(DbContextOptions<PgsqlContext> options) : DbContext(op
modelBuilder.Entity<Chapter>() modelBuilder.Entity<Chapter>()
.Navigation(c => c.ParentManga) .Navigation(c => c.ParentManga)
.AutoInclude(); .AutoInclude();
modelBuilder.Entity<Manga>()
.Navigation(m => m.Chapters)
.AutoInclude();
//Manga owns MangaAltTitles //Manga owns MangaAltTitles
modelBuilder.Entity<Manga>() modelBuilder.Entity<Manga>()
.OwnsMany<MangaAltTitle>(m => m.AltTitles) .OwnsMany<MangaAltTitle>(m => m.AltTitles)
.WithOwner(); .WithOwner();
modelBuilder.Entity<Manga>()
.Navigation(m => m.AltTitles)
.AutoInclude();
//Manga owns Links //Manga owns Links
modelBuilder.Entity<Manga>() modelBuilder.Entity<Manga>()
.OwnsMany<Link>(m => m.Links) .OwnsMany<Link>(m => m.Links)
.WithOwner(); .WithOwner();
modelBuilder.Entity<Manga>()
.Navigation(m => m.Links)
.AutoInclude();
//Manga has many Tags associated with many Manga //Manga has many Tags associated with many Manga
modelBuilder.Entity<Manga>() modelBuilder.Entity<Manga>()
.HasMany<MangaTag>(m => m.MangaTags) .HasMany<MangaTag>(m => m.MangaTags)
@ -155,6 +160,9 @@ public class PgsqlContext(DbContextOptions<PgsqlContext> options) : DbContext(op
r => r.HasOne(typeof(Manga)).WithMany().HasForeignKey("MangaIds").HasPrincipalKey(nameof(Manga.MangaId)), r => r.HasOne(typeof(Manga)).WithMany().HasForeignKey("MangaIds").HasPrincipalKey(nameof(Manga.MangaId)),
j => j.HasKey("MangaTagIds", "MangaIds") j => j.HasKey("MangaTagIds", "MangaIds")
); );
modelBuilder.Entity<Manga>()
.Navigation(m => m.MangaTags)
.AutoInclude();
//Manga has many Authors associated with many Manga //Manga has many Authors associated with many Manga
modelBuilder.Entity<Manga>() modelBuilder.Entity<Manga>()
.HasMany<Author>(m => m.Authors) .HasMany<Author>(m => m.Authors)
@ -164,6 +172,9 @@ public class PgsqlContext(DbContextOptions<PgsqlContext> options) : DbContext(op
r => r.HasOne(typeof(Manga)).WithMany().HasForeignKey("MangaIds").HasPrincipalKey(nameof(Manga.MangaId)), r => r.HasOne(typeof(Manga)).WithMany().HasForeignKey("MangaIds").HasPrincipalKey(nameof(Manga.MangaId)),
j => j.HasKey("AuthorIds", "MangaIds") j => j.HasKey("AuthorIds", "MangaIds")
); );
modelBuilder.Entity<Manga>()
.Navigation(m => m.Authors)
.AutoInclude();
//LocalLibrary has many Mangas //LocalLibrary has many Mangas
modelBuilder.Entity<LocalLibrary>() modelBuilder.Entity<LocalLibrary>()
@ -171,11 +182,8 @@ public class PgsqlContext(DbContextOptions<PgsqlContext> options) : DbContext(op
.WithOne(m => m.Library) .WithOne(m => m.Library)
.HasForeignKey(m => m.LibraryId) .HasForeignKey(m => m.LibraryId)
.OnDelete(DeleteBehavior.SetNull); .OnDelete(DeleteBehavior.SetNull);
modelBuilder.Entity<Manga>()
//LibraryConnector Types .Navigation(m => m.Library)
modelBuilder.Entity<LibraryConnector>() .AutoInclude();
.HasDiscriminator(l => l.LibraryType)
.HasValue<Komga>(LibraryType.Komga)
.HasValue<Kavita>(LibraryType.Kavita);
} }
} }

View File

@ -1,4 +1,5 @@
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using API.Schema.Contexts;
using Newtonsoft.Json; using Newtonsoft.Json;
namespace API.Schema.Jobs; namespace API.Schema.Jobs;
@ -26,6 +27,7 @@ public class DownloadAvailableChaptersJob : Job
protected override IEnumerable<Job> RunInternal(PgsqlContext context) protected override IEnumerable<Job> RunInternal(PgsqlContext context)
{ {
context.Attach(Manga);
return Manga.Chapters.Select(chapter => new DownloadSingleChapterJob(chapter, this)); return Manga.Chapters.Select(chapter => new DownloadSingleChapterJob(chapter, this));
} }
} }

View File

@ -1,4 +1,5 @@
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using API.Schema.Contexts;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Newtonsoft.Json; using Newtonsoft.Json;
@ -27,6 +28,7 @@ public class DownloadMangaCoverJob : Job
protected override IEnumerable<Job> RunInternal(PgsqlContext context) protected override IEnumerable<Job> RunInternal(PgsqlContext context)
{ {
context.Attach(Manga);
try try
{ {
Manga.CoverFileNameInCache = Manga.MangaConnector.SaveCoverImageToCache(Manga); Manga.CoverFileNameInCache = Manga.MangaConnector.SaveCoverImageToCache(Manga);

View File

@ -2,6 +2,7 @@
using System.IO.Compression; using System.IO.Compression;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using API.MangaDownloadClients; using API.MangaDownloadClients;
using API.Schema.Contexts;
using Newtonsoft.Json; using Newtonsoft.Json;
using SixLabors.ImageSharp; using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Formats.Jpeg; using SixLabors.ImageSharp.Formats.Jpeg;
@ -35,6 +36,7 @@ public class DownloadSingleChapterJob : Job
protected override IEnumerable<Job> RunInternal(PgsqlContext context) protected override IEnumerable<Job> RunInternal(PgsqlContext context)
{ {
context.Attach(Chapter);
string[] imageUrls = Chapter.ParentManga.MangaConnector.GetChapterImageUrls(Chapter); string[] imageUrls = Chapter.ParentManga.MangaConnector.GetChapterImageUrls(Chapter);
if (imageUrls.Length < 1) if (imageUrls.Length < 1)
{ {

View File

@ -1,5 +1,6 @@
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema; using System.ComponentModel.DataAnnotations.Schema;
using API.Schema.Contexts;
using log4net; using log4net;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Newtonsoft.Json; using Newtonsoft.Json;
@ -62,14 +63,16 @@ public abstract class Job
{ {
Log.Debug($"Running job {JobId}"); Log.Debug($"Running job {JobId}");
using IServiceScope scope = serviceProvider.CreateScope(); using IServiceScope scope = serviceProvider.CreateScope();
PgsqlContext context = scope.ServiceProvider.GetRequiredService<PgsqlContext>();
try try
{ {
PgsqlContext context = scope.ServiceProvider.GetRequiredService<PgsqlContext>();
context.Attach(this);
this.state = JobState.Running; this.state = JobState.Running;
context.SaveChanges(); context.SaveChanges();
Job[] newJobs = RunInternal(context).ToArray(); Job[] newJobs = RunInternal(context).ToArray();
this.state = JobState.Completed; this.state = JobState.Completed;
context.SaveChanges();
context.Jobs.AddRange(newJobs); context.Jobs.AddRange(newJobs);
context.SaveChanges(); context.SaveChanges();
Log.Info($"Job {JobId} completed. Generated {newJobs.Length} new jobs."); Log.Info($"Job {JobId} completed. Generated {newJobs.Length} new jobs.");

View File

@ -1,4 +1,5 @@
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using API.Schema.Contexts;
namespace API.Schema.Jobs; namespace API.Schema.Jobs;

View File

@ -1,4 +1,5 @@
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using API.Schema.Contexts;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Newtonsoft.Json; using Newtonsoft.Json;
@ -32,6 +33,7 @@ public class MoveMangaLibraryJob : Job
protected override IEnumerable<Job> RunInternal(PgsqlContext context) protected override IEnumerable<Job> RunInternal(PgsqlContext context)
{ {
context.Attach(Manga);
Dictionary<Chapter, string> oldPath = Manga.Chapters.ToDictionary(c => c, c => c.FullArchiveFilePath); Dictionary<Chapter, string> oldPath = Manga.Chapters.ToDictionary(c => c, c => c.FullArchiveFilePath);
Manga.Library = ToLibrary; Manga.Library = ToLibrary;
try try

View File

@ -1,5 +1,5 @@
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using API.Schema.MangaConnectors; using API.Schema.Contexts;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Newtonsoft.Json; using Newtonsoft.Json;
@ -31,6 +31,7 @@ public class RetrieveChaptersJob : Job
protected override IEnumerable<Job> RunInternal(PgsqlContext context) protected override IEnumerable<Job> RunInternal(PgsqlContext context)
{ {
context.Attach(Manga);
// This gets all chapters that are not downloaded // This gets all chapters that are not downloaded
Chapter[] allChapters = Manga.MangaConnector.GetChapters(Manga, Language); Chapter[] allChapters = Manga.MangaConnector.GetChapters(Manga, Language);
Chapter[] newChapters = allChapters.Where(chapter => context.Chapters.Contains(chapter) == false).ToArray(); Chapter[] newChapters = allChapters.Where(chapter => context.Chapters.Contains(chapter) == false).ToArray();

View File

@ -1,4 +1,5 @@
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using API.Schema.Contexts;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Newtonsoft.Json; using Newtonsoft.Json;
@ -27,6 +28,7 @@ public class UpdateFilesDownloadedJob : Job
protected override IEnumerable<Job> RunInternal(PgsqlContext context) protected override IEnumerable<Job> RunInternal(PgsqlContext context)
{ {
context.Attach(Manga);
foreach (Chapter chapter in Manga.Chapters) foreach (Chapter chapter in Manga.Chapters)
chapter.Downloaded = chapter.CheckDownloaded(); chapter.Downloaded = chapter.CheckDownloaded();

View File

@ -1,4 +1,6 @@
namespace API.Schema.MangaConnectors; using API.Schema.Contexts;
namespace API.Schema.MangaConnectors;
public class Global : MangaConnector public class Global : MangaConnector
{ {

View File

@ -1,4 +1,5 @@
using API.Schema; using API.Schema;
using API.Schema.Contexts;
using API.Schema.Jobs; using API.Schema.Jobs;
using API.Schema.MangaConnectors; using API.Schema.MangaConnectors;
using API.Schema.NotificationConnectors; using API.Schema.NotificationConnectors;
@ -30,12 +31,7 @@ public static class Tranga
} }
IServiceProvider serviceProvider = (IServiceProvider)serviceProviderObj!; IServiceProvider serviceProvider = (IServiceProvider)serviceProviderObj!;
using IServiceScope scope = serviceProvider.CreateScope(); using IServiceScope scope = serviceProvider.CreateScope();
PgsqlContext? context = scope.ServiceProvider.GetService<PgsqlContext>(); NotificationsContext context = scope.ServiceProvider.GetRequiredService<NotificationsContext>();
if (context is null)
{
Log.Error("PgsqlContext is null");
return;
}
try try
{ {
@ -64,12 +60,7 @@ public static class Tranga
{ {
Log.Info($"Sending notifications for {urgency}"); Log.Info($"Sending notifications for {urgency}");
using IServiceScope scope = serviceProvider.CreateScope(); using IServiceScope scope = serviceProvider.CreateScope();
PgsqlContext? context = scope.ServiceProvider.GetService<PgsqlContext>(); NotificationsContext context = scope.ServiceProvider.GetRequiredService<NotificationsContext>();
if (context is null)
{
Log.Error("PgsqlContext is null");
return;
}
List<Notification> notifications = context.Notifications.Where(n => n.Urgency == urgency).ToList(); List<Notification> notifications = context.Notifications.Where(n => n.Urgency == urgency).ToList();
if (!notifications.Any()) if (!notifications.Any())
@ -117,6 +108,8 @@ public static class Tranga
} }
Log.Info(TRANGA); Log.Info(TRANGA);
Log.Info("Loading Jobs");
context.Jobs.Load();
Log.Info("JobStarter Thread running."); Log.Info("JobStarter Thread running.");
while (true) while (true)
{ {
@ -146,7 +139,7 @@ public static class Tranga
List<Job> dueJobs = waitingJobs.Where(j => j.NextExecution < DateTime.UtcNow).ToList(); List<Job> dueJobs = waitingJobs.Where(j => j.NextExecution < DateTime.UtcNow).ToList();
List<MangaConnector> busyConnectors = GetBusyConnectors(runningJobs); List<MangaConnector> busyConnectors = GetBusyConnectors(runningJobs);
List<Job> startJobs = FilterJobPreconditions(dueJobs, busyConnectors); List<Job> startJobs = FilterJobPreconditions(context, dueJobs, busyConnectors);
//Start Jobs that are allowed to run (preconditions match) //Start Jobs that are allowed to run (preconditions match)
foreach (Job job in startJobs) foreach (Job job in startJobs)
@ -194,9 +187,13 @@ public static class Tranga
return busyConnectors.ToList(); return busyConnectors.ToList();
} }
private static List<Job> FilterJobPreconditions(List<Job> dueJobs, List<MangaConnector> busyConnectors) => private static List<Job> FilterJobPreconditions(PgsqlContext context, List<Job> dueJobs, List<MangaConnector> busyConnectors) =>
dueJobs dueJobs
.Where(j => j.DependenciesFulfilled) .Where(j =>
{
context.Entry(j).Collection(j => j.DependsOnJobs).Load(LoadOptions.ForceIdentityResolution);
return j.DependenciesFulfilled;
})
.Where(j => .Where(j =>
{ {
//Filter jobs with busy connectors //Filter jobs with busy connectors