NCronJob-Dev / NCronJob

A Job Scheduler sitting on top of IHostedService in dotnet.
https://docs.ncronjob.dev/
MIT License
158 stars 11 forks source link

Jobs added during runtime do not run #100

Closed IvaTutis closed 3 weeks ago

IvaTutis commented 1 month ago

Bug description

The Job will be triggered at the expected time if it is added to the runtime registry at the start of the application. When the job is added later to the registry using the same service, it will appear in the registry (breakpoint view) as it should, but will not be triggered at the expected time.

The instant job registration and execution works fine.

The jobs below are added and deleted from the registries in the same manner as in the documentation and other issues. (referencing issue and docs)

Context

I am making a task scheduler, and am using NCronJob as an alternative to Quartz. During runtime, I want to have the user define a job that is triggered on a defined, repeating schedule. The jobs that are allready defined in the database are added to the registry using a hosted service during runtime, after startup. These jobs are can be removed and new jobs can be added through the runtime registry.
We did not make an interface for an update at this time

Task

In the example provided below, one task can have N triggers, where every trigger will equate one job registered during runtime. When unregistering a task, all related jobs will be unregistered.

Custom Interface for job registries

All the additions and deletions of jobsfrom the registry are done through the same service, which shows the same behaviour both as a transient and a singleton: service example

classDiagram
    class IJobRegistrationService {
        <<interface>>
        +RegisterOneTimeJob(AutomatedTask task) Task
        +UpsertRecurringJobRegistration(AutomatedTask task) Task
        +TryUnregisteringRecurringJob(Guid taskId) Task
    }

    class JobRegistrationService {
        -IRuntimeJobRegistry _jobRegistry
        -IInstantJobRegistry _instantJobRegistry
        -ILogger<JobRegistrationService> _logger
        -Func<Guid, Guid, string> JobName
        -Func<Guid> ManualJobTriggerId
        +RegisterOneTimeJob(AutomatedTask task) Task
        +UpsertRecurringJobRegistration(AutomatedTask task) Task
        +TryUnregisteringRecurringJob(Guid taskId) Task
        -RegisterJobWithSingleTrigger(Guid taskId, PeriodicallyTrigger trigger) void
        -DeleteAllJobsForTask(Guid taskId) void
        -IsJobRelatedToAutomatedTask(RecurringJobSchedule job, Guid taskId) bool
    }

    class IRuntimeJobRegistry {
        <<interface>>
    }

    class IInstantJobRegistry {
        <<interface>>
    }

    class ILogger {
        <<interface>>
    }

    JobRegistrationService ..|> IJobRegistrationService
    JobRegistrationService --> IRuntimeJobRegistry
    JobRegistrationService --> IInstantJobRegistry
    JobRegistrationService --> ILogger

Expected behavior

The jobs will run at the expected time regardless of how they were registered (given they are well formed and saved in the registry)

Version information

linkdotnet commented 1 month ago

Hey @IvaTutis,

thanks for raising the issue. Do you have a reproducible example by any chance?.

I tried a very minimal setup:

using NCronJob;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddNCronJob();

var app = builder.Build();

app.MapGet("/", (IRuntimeJobRegistry registry) =>
{
    registry.AddJob(j => j.AddJob(() => { Console.WriteLine("HEY"); }, "* * * * * *"));
});

app.Run();

If you hit the "/" endpoint with a browser you will see "HEY" every second on the console. So jobs are executed.

IvaTutis commented 3 weeks ago

Hey @linkdotnet

Sorry for the late reply. I created a small Blazor app to showcase the bug in a repeatable enviroment.

All of the jobs that are added to the RuntimeRegistry here are added in the same manner, and they appear in the registry when added (and I can wipe them from it well).

The main issue is that only the ones that are added >>RIGHT AFTER STARTUP via TaskSyncService<< seem to work. The ones added via the UI seem to not fire.

The example you provice above with app.MapGet would therefore technically fit the first case.

linkdotnet commented 3 weeks ago

Hey @IvaTutis

Thanks for the repro! That really helped, and yes, indeed, there is/was a bug. I am currently fixing it.

Sorry for the late reply.

We all have private lives and responsibilities - no need to apologize. I will push a fix in a few seconds.

linkdotnet commented 3 weeks ago

New version (currently preview): https://www.nuget.org/packages/NCronJob/3.3.1-preview

It would be great if you can report back, whether or not that fixes your case. Thanks.

IvaTutis commented 3 weeks ago

Tested on my projects, runtime jobs now fire as expected. Will update on a different issue if anything else pops up.

Thank you for the fix, and great work! 🐛 ✨