Fix infinity joby (because we did not create new Scope on every cycle)

This commit is contained in:
Glax 2025-05-18 20:31:46 +02:00
parent 02ab3d8cae
commit 33856f9927
3 changed files with 30 additions and 24 deletions

View File

@ -124,7 +124,7 @@ using (IServiceScope scope = app.Services.CreateScope())
context.Jobs.AddRange(context.Jobs.Where(j => j.JobType == JobType.DownloadAvailableChaptersJob) context.Jobs.AddRange(context.Jobs.Where(j => j.JobType == JobType.DownloadAvailableChaptersJob)
.Include(downloadAvailableChaptersJob => ((DownloadAvailableChaptersJob)downloadAvailableChaptersJob).Manga) .Include(downloadAvailableChaptersJob => ((DownloadAvailableChaptersJob)downloadAvailableChaptersJob).Manga)
.ToList() .ToList()
.Select(dacj => new UpdateChaptersDownloadedJob(((DownloadAvailableChaptersJob)dacj).Manga, 0))); .Select(dacj => new UpdateChaptersDownloadedJob(((DownloadAvailableChaptersJob)dacj).Manga, 0, dacj)));
context.Jobs.RemoveRange(context.Jobs.Where(j => j.state == JobState.Completed && j.RecurrenceMs < 1)); 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)) foreach (Job job in context.Jobs.Where(j => j.state == JobState.Running))
{ {

View File

@ -66,32 +66,31 @@ public abstract class Job
this.Log = LogManager.GetLogger(this.GetType()); this.Log = LogManager.GetLogger(this.GetType());
} }
public IEnumerable<Job> Run(PgsqlContext context) public IEnumerable<Job> Run(PgsqlContext context, ref bool running)
{ {
Log.Info($"Running job {JobId}"); Log.Info($"Running job {JobId}");
DateTime jobStart = DateTime.UtcNow; DateTime jobStart = DateTime.UtcNow;
context.Attach(this);
Job[]? ret = null; Job[]? ret = null;
try try
{ {
this.state = JobState.Running; this.state = JobState.Running;
context.SaveChanges(); context.SaveChanges();
running = true;
ret = RunInternal(context).ToArray(); ret = RunInternal(context).ToArray();
Log.Info($"Job {JobId} completed. Generated {ret.Length} new jobs.");
this.state = this.RecurrenceMs > 0 ? JobState.CompletedWaiting : JobState.Completed; this.state = this.RecurrenceMs > 0 ? JobState.CompletedWaiting : JobState.Completed;
this.LastExecution = DateTime.UtcNow; this.LastExecution = DateTime.UtcNow;
context.Jobs.AddRange(ret);
Log.Info($"Job {JobId} completed. Generated {ret.Length} new jobs.");
context.SaveChanges(); context.SaveChanges();
} }
catch (Exception e) catch (Exception e)
{ {
if (e is not DbUpdateException) if (e is not DbUpdateException)
{ {
Log.Error($"Failed to run job {JobId}", e);
this.state = JobState.Failed; this.state = JobState.Failed;
this.Enabled = false; this.Enabled = false;
this.LastExecution = DateTime.UtcNow; this.LastExecution = DateTime.UtcNow;
Log.Error($"Failed to run job {JobId}", e);
context.SaveChanges(); context.SaveChanges();
} }
else else
@ -100,6 +99,19 @@ public abstract class Job
} }
} }
try
{
if (ret != null)
{
context.Jobs.AddRange(ret);
context.SaveChanges();
}
}
catch (DbUpdateException e)
{
Log.Error($"Failed to update Database {JobId}", e);
}
Log.Info($"Finished Job {JobId}! (took {DateTime.UtcNow.Subtract(jobStart).TotalMilliseconds}ms)"); Log.Info($"Finished Job {JobId}! (took {DateTime.UtcNow.Subtract(jobStart).TotalMilliseconds}ms)");
return ret ?? []; return ret ?? [];
} }

View File

@ -117,32 +117,21 @@ public static class Tranga
return; return;
} }
IServiceProvider serviceProvider = (IServiceProvider)serviceProviderObj; IServiceProvider serviceProvider = (IServiceProvider)serviceProviderObj;
using IServiceScope scope = serviceProvider.CreateScope();
while (true) while (true)
{ {
Log.Debug("Starting Job-Cycle..."); Log.Debug("Starting Job-Cycle...");
DateTime cycleStart = DateTime.UtcNow; DateTime cycleStart = DateTime.UtcNow;
using IServiceScope scope = serviceProvider.CreateScope();
PgsqlContext cycleContext = scope.ServiceProvider.GetRequiredService<PgsqlContext>(); PgsqlContext cycleContext = scope.ServiceProvider.GetRequiredService<PgsqlContext>();
Log.Debug("Loading Jobs...");
DateTime loadStart = DateTime.UtcNow;
Log.Debug($"Jobs Loaded! (took {DateTime.UtcNow.Subtract(loadStart).TotalMilliseconds}ms)");
//Update finished Jobs to new states
IQueryable<Job> completedJobs = cycleContext.Jobs.Where(j => j.state == JobState.Completed);
foreach (Job completedJob in completedJobs)
if (completedJob.RecurrenceMs <= 0)
{
cycleContext.Jobs.Remove(completedJob);
}
//Retrieve waiting and due Jobs List<Job> runningJobs = cycleContext.Jobs.Where(j => j.state == JobState.Running).ToList();
IQueryable<Job> runningJobs = cycleContext.Jobs.Where(j => j.state == JobState.Running);
DateTime filterStart = DateTime.UtcNow; DateTime filterStart = DateTime.UtcNow;
Log.Debug("Filtering Jobs..."); Log.Debug("Filtering Jobs...");
List<MangaConnector> busyConnectors = GetBusyConnectors(runningJobs); List<MangaConnector> busyConnectors = GetBusyConnectors(runningJobs);
IQueryable<Job> waitingJobs = cycleContext.Jobs.Where(j => j.state == JobState.CompletedWaiting || j.state == JobState.FirstExecution); List<Job> waitingJobs = cycleContext.Jobs.Where(j => j.state == JobState.CompletedWaiting || j.state == JobState.FirstExecution).ToList();
List<Job> dueJobs = FilterDueJobs(waitingJobs); List<Job> dueJobs = FilterDueJobs(waitingJobs);
List<Job> jobsWithoutBusyConnectors = FilterJobWithBusyConnectors(dueJobs, busyConnectors); List<Job> jobsWithoutBusyConnectors = FilterJobWithBusyConnectors(dueJobs, busyConnectors);
List<Job> jobsWithoutMissingDependencies = FilterJobDependencies(jobsWithoutBusyConnectors); List<Job> jobsWithoutMissingDependencies = FilterJobDependencies(jobsWithoutBusyConnectors);
@ -175,16 +164,21 @@ public static class Tranga
//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)
{ {
bool running = false;
Thread t = new(() => Thread t = new(() =>
{ {
using IServiceScope jobScope = serviceProvider.CreateScope(); using IServiceScope jobScope = serviceProvider.CreateScope();
PgsqlContext jobContext = jobScope.ServiceProvider.GetRequiredService<PgsqlContext>(); PgsqlContext jobContext = jobScope.ServiceProvider.GetRequiredService<PgsqlContext>();
jobContext.Jobs.Find(job.JobId)?.Run(jobContext); //FIND the job IN THE NEW CONTEXT!!!!!!! SO WE DON'T GET TRACKING PROBLEMS AND AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA if (jobContext.Jobs.Find(job.JobId) is not { } inContext)
return;
inContext.Run(jobContext, ref running); //FIND the job IN THE NEW CONTEXT!!!!!!! SO WE DON'T GET TRACKING PROBLEMS AND AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
}); });
RunningJobs.Add(t, job); RunningJobs.Add(t, job);
t.Start(); t.Start();
while(!running)
Thread.Sleep(10);
} }
Log.Debug($"Jobs Completed: {completedJobs.Count()} Running: {runningJobs.Count()}\n" + Log.Debug($"Running: {runningJobs.Count()}\n" +
$"Waiting: {waitingJobs.Count()}\n" + $"Waiting: {waitingJobs.Count()}\n" +
$"\tof which Due: {dueJobs.Count()}\n" + $"\tof which Due: {dueJobs.Count()}\n" +
$"\t\tof which can be started: {jobsWithoutMissingDependencies.Count()}\n" + $"\t\tof which can be started: {jobsWithoutMissingDependencies.Count()}\n" +
@ -211,7 +205,7 @@ public static class Tranga
} }
} }
private static List<MangaConnector> GetBusyConnectors(IQueryable<Job> runningJobs) private static List<MangaConnector> GetBusyConnectors(List<Job> runningJobs)
{ {
HashSet<MangaConnector> busyConnectors = new(); HashSet<MangaConnector> busyConnectors = new();
foreach (Job runningJob in runningJobs) foreach (Job runningJob in runningJobs)
@ -222,7 +216,7 @@ public static class Tranga
return busyConnectors.ToList(); return busyConnectors.ToList();
} }
private static List<Job> FilterDueJobs(IQueryable<Job> jobs) => private static List<Job> FilterDueJobs(List<Job> jobs) =>
jobs.ToList() jobs.ToList()
.Where(j => j.NextExecution < DateTime.UtcNow) .Where(j => j.NextExecution < DateTime.UtcNow)
.ToList(); .ToList();