NCronJob-Dev / NCronJob

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

[MaybeBug/MaybeDoc] How to model complex dependencies #101

Closed nulltoken closed 3 weeks ago

nulltoken commented 3 weeks ago

:wave: @linkdotnet

I either might need some (very welcome) guidance or there's some kind of a dark corner in NCronJob.

This graph sold me on NCronJob.

However, I can't seem to find how to properly register the Jobs to make this work. And I haven't found a test showing any dependency more than one level deep.

The doc states that RunJob can be chained to allow multiple jobs to run after the completion of the main job.. Which would allow some

A  ---  success  ---  B
                  |_  C

My understanding is that ExecuteWhen can be chained as well to model

A  ---  success  ---  B
    |_  success  ---  C

Would it be possible to add a unit test showing how to properly register this kind of dependency chain?

A  ---  success  ---  B --- success --- C
nulltoken commented 3 weeks ago

FWIW I've tried the following...

        *.AddNCronJob(n => n.AddJob<B>()
            .ExecuteWhen(success: s => s.RunJob<C>()));

        *.AddNCronJob(n => n.AddJob<A>()
            .ExecuteWhen(success: s => s.RunJob<A>()));

... but it seems that there's no recursive analysis of the dependencies of B when building the JobDefiniton of A (or I haven't been able to find it :-/)

linkdotnet commented 3 weeks ago

Hey @nulltoken

You might be on to something. So the A --- success --- B --- success --- C should be modelled like this:

using NCronJob;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddNCronJob(
    o => o.AddJob<JobA>()
        .ExecuteWhen(s => s.RunJob<JobB>())
        .AddJob<JobB>()
        .ExecuteWhen(s => s.RunJob<JobC>()));

var app = builder.Build();

app.MapGet("/", (IInstantJobRegistry registry) =>
{
    registry.RunInstantJob<JobA>();
});

app.Run();

class JobA : IJob
{
    public Task RunAsync(IJobExecutionContext context, CancellationToken token)
    {
        Console.WriteLine("JobA");
        return Task.CompletedTask;
    }
}

class JobB : IJob
{
    public Task RunAsync(IJobExecutionContext context, CancellationToken token)
    {
        Console.WriteLine("JobB");
        return Task.CompletedTask;
    }
}

class JobC : IJob
{
    public Task RunAsync(IJobExecutionContext context, CancellationToken token)
    {
        Console.WriteLine("JobC");
        return Task.CompletedTask;
    }
}

But that doesn't work as expected.

A  ---  success  ---  B
    |_  success  ---  C

Exactly this should be similar possible. I will check those cases. Thanks!

linkdotnet commented 3 weeks ago

Okay I found a few issues! Will push a fix soon with updated documentation

linkdotnet commented 3 weeks ago

So both bugs are fixed, I did add some test and updated the documentation. Will put the links here once everything is published

linkdotnet commented 3 weeks ago

Latest package: https://www.nuget.org/packages/NCronJob/3.2.0 Here is the updated chapter: https://docs.ncronjob.dev/features/model-dependencies/#run-mutliple-jobs-after-the-completion-of-a-job

Thanks again for bringing up the issues @nulltoken ! Much appreciated

nulltoken commented 3 weeks ago

You might be on to something.

@linkdotnet Duh. My attempts were actually relying on calling the builder twice, not AddNCronJob... Sorry for the misleading (too hastily typed) pear-shaped repro :-/

So both bugs are fixed, I did add some test and updated the documentation. Will put the links here once everything is published

...but you got the gist of it and eventually, once again, saved the world. Thanks for that! I've tested it and it now works as expected.

One thing the doco may benefit from would maybe to also register JobC (in order to avoid the warning in the logs).

linkdotnet commented 3 weeks ago

Good point! Will update the docs