1

I got a project built under ASP Core 2 that utilizes the Quartz.NET scheduler 3-beta1

I've got the following job that i want to execute:

public class TestJob: IJob
{
    private readonly AppDbContext _dbContext;
    public TestJob(AppDbContext dbContext)
    {
        _dbContext = dbContext;
    }

    public Task Execute(IJobExecutionContext context)
    {
        Debug.WriteLine("Test check at " + DateTime.Now);

        var testRun = _dbContext.TestTable.Where(o => o.CheckNumber > 10).ToList();

        Debug.WriteLine(testRun.Count);

        return Task.CompletedTask;
    }
}

Unfortunately it never works and there are not error logs to indicate an issue.

Yet when i remove everything and just leave the Debug.WriteLine it works as per below example.

public class TestJob: IJob
    {
        public Task Execute(IJobExecutionContext context)
        {
            Debug.WriteLine("Test check at " + DateTime.Now);

            return Task.CompletedTask;
        }
    }

How can i get my job to execute the database call?

EDIT 1: Job Creation

var schedulerFactory = new StdSchedulerFactory(properties);
            _scheduler = schedulerFactory.GetScheduler().Result;
            _scheduler.Start().Wait();

var testJob = JobBuilder.Create<TestJob>()
    .WithIdentity("TestJobIdentity")
    .Build();
var testTrigger = TriggerBuilder.Create()
    .WithIdentity("TestJobTrigger")
    .StartNow()
    .WithSimpleSchedule(x => x.WithIntervalInMinutes(1).RepeatForever())
    .Build();


if (CheckIfJobRegistered(testJob.Key).Result == false)
    _scheduler.ScheduleJob(testJob, testTrigger).Wait();
Aeseir
  • 7,754
  • 10
  • 58
  • 107
  • Did you use any Factory for your job creation? – Rabban Dec 19 '17 at 08:38
  • yea, i'll put up my code now for the job creation – Aeseir Dec 19 '17 at 09:41
  • The `JobBuilder` is not a factory, it creates a definition for the job. Quartz creates the job shortly before it got executed. But Quartz can't know how to create the job with the custom constructor. Either you need a empty default constructor or a custom JobFactory to create the job. – Rabban Dec 19 '17 at 10:28
  • Not sure i understand what you mean. The job is created, just doesn't execute when i inject a dbcontext – Aeseir Dec 19 '17 at 10:30
  • But who creates the job? Your _Job Creation_ in your edit don't creates the job, It just schedules it. Maybe your example is not complete, but i can't see anything where you inject the dbcontext or the job gets created. – Rabban Dec 19 '17 at 10:34
  • Do you have an example of this? This code is based on the quartz tutorials (and some other research). From my understanding this starts the scheduler and the schedules this job for execution. Which will execute the job every one minute without fail unless i inject dbcontext, in which case it craps out – Aeseir Dec 19 '17 at 10:39
  • _When a trigger fires, the JobDetail (instance definition) it is associated to is loaded, and the job class it refers to is instantiated via the JobFactory configured on the Scheduler. The default JobFactory simply calls the default constructor of the job class using Activator.CreateInstance, then attempts to call setter properties on the class that match the names of keys within the JobDataMap. You may want to create your own implementation of JobFactory to accomplish things such as having your application’s IoC or DI container produce/initialize the job instance._ – Rabban Dec 19 '17 at 10:50
  • You can read more about this [here](https://www.quartz-scheduler.net/documentation/quartz-3.x/tutorial/more-about-jobs.html). The `Activator.CreateInstance` can't find a empty default constructor and through this can't create the job. Then Quartz will swallow this exception and you see nothing from this behaviour. – Rabban Dec 19 '17 at 10:52
  • ahh, no wonder i was dropping the ball, there is a lot I missed – Aeseir Dec 19 '17 at 10:57
  • Did this help you to solve the issue or do you need a example for the factory? – Rabban Dec 19 '17 at 10:59
  • If you got a example of simple setup (how to createa and register this factory) would be awesome – Aeseir Dec 19 '17 at 11:00

1 Answers1

1

The main problem here is that Quartz can't create the job and swallows the exception.

The Documentation states:

When a trigger fires, the JobDetail (instance definition) it is associated to is loaded, and the job class it refers to is instantiated via the JobFactory configured on the Scheduler. The default JobFactory simply calls the default constructor of the job class using Activator.CreateInstance, then attempts to call setter properties on the class that match the names of keys within the JobDataMap. You may want to create your own implementation of JobFactory to accomplish things such as having your application’s IoC or DI container produce/initialize the job instance.

Quartz provides the IJobFactory to achieve that. And it works really good with Dependency Injection. A JobFactory can look like this:

public class JobFactory : IJobFactory
{
    //TypeFactory is just the DI Container of your choice
    protected readonly TypeFactory Factory;

    public JobFactory(TypeFactory factory)
    {
        Factory = factory;
    }

    public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler)
    {
        try
        {
            return Factory.Create(bundle.JobDetail.JobType) as IJob;
        }
        catch (Exception e)
        {
            //Log the error and return null
            //every exception thrown will be swallowed by Quartz 
            return null;
        }
    }

    public void ReturnJob(IJob job)
    {
        //Don't forget to implement this,
        //or the memory will not released
        Factory.Release(job);
    }
}

Then just register your JobFactory with the scheduler and everything should work:

_scheduler.JobFactory = new JobFactory(/*container of choice*/);

Edit:

Additionally you can take a look to one of my previous answers.

Rabban
  • 2,451
  • 1
  • 19
  • 21
  • Thanks, i will keep investigating, so far i have not been able to inject dbcontext using the code there so still can't execute the query on db. – Aeseir Dec 19 '17 at 11:51
  • I use the standard Asp Core dependency injection which has all my services registered in StartUp app. – Aeseir Dec 19 '17 at 11:56
  • @Aeseir And my linked answer didn't help? – Rabban Dec 19 '17 at 11:58
  • While it help formulate an understanding, i still haven't been able to inject my dbcontex and as such make queries. Googling around I haven't seen a single answer out there that shows me how to inject a actual DbContext in a job. – Aeseir Dec 19 '17 at 12:09
  • @Aeseir Are you sure it is registered in your container? And what exception do you get when you try to resolve the job/dbcontext from the container? – Rabban Dec 19 '17 at 12:18
  • regarding container creation would you do this in Configure method of StartUp class or within the Quartz constructor? I am trying all permutations now to see if something hits. – Aeseir Dec 19 '17 at 23:57
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/161598/discussion-between-rabban-and-aeseir). – Rabban Dec 20 '17 at 08:49