Reputation: 161
I use Quartz.NET with ASP .Net Core. I want to create scheduler for my app business logic (HelloWorldJob=)), …which can started to execute by event, can paused and resumed by user commands. But something is going wrong, possibly from the beginning(.
So, I created class QuartzHostedService class. In it I configurated job, trigger and scheduler for my business logic. QuartzHostedService public async Task StartAsync(CancellationToken cancellationToken) ” is being executed only once, and started _scheduler with my job - HelloWorldJob. But! The job was never executed! Why?
public class QuartzHostedService : IHostedService
{
private readonly ISchedulerFactory _schedulerFactory;
public IScheduler? _scheduler;
private readonly ILogger<QuartzHostedService> _logger;
private readonly InitializationModuleConfiguration _initializationModuleConfiguration;
private IJobDetail _jobDetail;
private bool isEnabled;
public QuartzHostedService(
ISchedulerFactory schedulerFactory,
InitializationModuleConfiguration initializationModuleConfiguration,
ILogger<QuartzHostedService> logger
)
{
_logger = logger;
_schedulerFactory = schedulerFactory;
_initializationModuleConfiguration = initializationModuleConfiguration;
}
public async Task StartAsync(CancellationToken cancellationToken)
{
//StdSchedulerFactory factory = new StdSchedulerFactory();
_scheduler = await _schedulerFactory.GetScheduler();
await _scheduler.Start();
// define the job and tie it to our HelloWorldJob class
_jobDetail = JobBuilder.Create<HelloWorldJob>()
.WithIdentity("_job", "group")
.Build();
////When you wish to schedule a job, you instantiate a trigger
////and 'tune' its properties to provide the scheduling you wish to have.
ITrigger _trigger = TriggerBuilder.Create()
.WithIdentity("_trigger", "group")
.StartNow()
.WithSimpleSchedule(x => x
.WithIntervalInSeconds(5)
.RepeatForever())
.Build();
if (_initializationModuleConfiguration.DataLoaderStarted && !isEnabled)
{
// Tell quartz to schedule the job using our trigger
await _scheduler.ScheduleJob(_jobDetail, _trigger);
isEnabled = true;
}
_logger.LogInformation("Execute");
}
public Task StopAsync(CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
}
public class Startup
{
.......
.......
services.AddQuartzHostedService(
quartz => quartz.WaitForJobsToComplete = true);
services.AddSingleton<Quartz.ISchedulerFactory, StdSchedulerFactory>();
services.AddSingleton<HelloWorldJob>();
services.AddHostedService<QuartzHostedService>();
[DisallowConcurrentExecution]
public class HelloWorldJob: IJob, IHelloWorldJob
{
private readonly ILogger<HelloWorldJob> _logger;
public HelloWorldJob(ILogger<HelloWorldJob> logger)
{
_logger = logger;
}
public Task Execute(IJobExecutionContext context)
{
_logger.LogInformation("Hello world!");
return Task.CompletedTask;
}
}
Upvotes: 2
Views: 2340
Reputation: 161
Corrected Startup, now it works:
Startup
services.AddQuartz(q =>
{
q.UseDefaultThreadPool(maxConcurrency: 1);
q.UseMicrosoftDependencyInjectionJobFactory();
});
services.AddQuartzHostedService(q => q.WaitForJobsToComplete = true);
services.AddSingleton<IDataProcessingModule,DataProcessingModule>();
services.AddSingleton<IDataLoaderModule, DataLoaderModule>();
services.AddSingleton<IKafkaSendingModule, KafkaSendingModule>();
QuartzHostedService
public QuartzHostedService(
ISchedulerFactory schedulerFactory,
InitializationModuleConfiguration initializationModuleConfiguration,
ILogger<QuartzHostedService> logger,
DataLoaderConfiguration dataLoaderConfiguration,
DataProcessingConfiguration dataProcessingConfiguration
)
{
_logger = logger;
_schedulerFactory = schedulerFactory;
_initializationModuleConfiguration = initializationModuleConfiguration;
_dataLoaderConfiguration = dataLoaderConfiguration;
_dataProcessingConfiguration = dataProcessingConfiguration;
}
public async Task StartAsync(CancellationToken cancellationToken)
{
_cancellationToken = cancellationToken;//???
_scheduler = await _schedulerFactory.GetScheduler(cancellationToken);
await _scheduler.Start(cancellationToken);
_jobDetailLoader = CreateJob<IDataLoaderModule>();
_jobDetailProcessing = CreateJob<IDataProcessingModule>();
if (_initializationModuleConfiguration.DataLoaderStarted)
{
await StartJobAsync<IDataLoaderModule>(_dataLoaderConfiguration.LoaderTimeoutMs);
}
if (_initializationModuleConfiguration.DataProcessingStarted)
{
await StartJobAsync<IDataProcessingModule>(_dataLoaderConfiguration.LoaderTimeoutMs);
}
}
public async Task StopAsync(CancellationToken cancellationToken)
{
await _scheduler.Shutdown(cancellationToken);
}
private IJobDetail CreateJob<TModule>() where TModule : IJob
{
var job = JobBuilder
.Create<TModule>()
.WithIdentity(typeof(TModule).Name, "group")
.StoreDurably()
.Build();
job.JobDataMap.Put("Status", "Created");
return job;
}
private ITrigger CreateTrigger<TModule>(int interval) where TModule : IJob
{
return TriggerBuilder
.Create()
.WithIdentity(typeof(TModule).Name, "group")
.ForJob(typeof(TModule).Name, "group")
.StartNow()
.WithSimpleSchedule(x => x
.WithInterval(TimeSpan.FromMilliseconds(interval))
.RepeatForever())
.Build();
}
public async Task StartJobAsync<TModule>(int interval) where TModule : IJob
{
try
{
var schedJobs = GetSchedJob(typeof(TModule).Name);
var status = schedJobs.JobDetail.JobDataMap.GetString("Status");
if (status == "Created")
{
var trigger = CreateTrigger<TModule>(interval);
await _scheduler.ScheduleJob(schedJobs.JobDetail, trigger, _cancellationToken); //cancellationToken
schedJobs.JobDetail.JobDataMap.Put("Status", "Runned");
}
await _scheduler.ResumeJob(schedJobs.JobDetail.Key, _cancellationToken);
}
catch (SchedulerException e)
{
_logger.LogError(e.ToString());
}
}
public async Task PauseJobAsync<TModule>() where TModule : IJob
{
try
{
var schedJobs = GetSchedJob(typeof(TModule).Name);
await _scheduler.PauseJob(schedJobs.JobDetail.Key, _cancellationToken);
schedJobs.JobDetail.JobDataMap.Put("Status", "Stopped");
}
catch (SchedulerException e)
{
_logger.LogError(e.ToString());
}
}
private (IScheduler Scheduler, IJobDetail JobDetail) GetSchedJob(string key)
{
IJobDetail job = key == nameof(IDataLoaderModule) ? _jobDetailLoader
: key == nameof(IDataProcessingModule) ? _jobDetailProcessing
: _jobDetailProcessing;
return (_scheduler, job);
}
}
}
Upvotes: 0
Reputation: 5144
Your code logic looks a bit messy, you can refer to my test code below (Since I don't know the logic of your InitializationModuleConfiguration
, I didn't inject this one):
QuartzHostedService:
public class QuartzHostedService : IHostedService
{
private readonly ISchedulerFactory _schedulerFactory;
private readonly IJobFactory _jobFactory;
public QuartzHostedService(
ISchedulerFactory schedulerFactory,
IJobFactory jobFactory)
{
_schedulerFactory = schedulerFactory;
_jobFactory = jobFactory;
}
public IScheduler Scheduler { get; set; }
public async Task StartAsync(CancellationToken cancellationToken)
{
Scheduler = await _schedulerFactory.GetScheduler(cancellationToken);
Scheduler.JobFactory = _jobFactory;
var job = CreateJob();
var trigger = CreateTrigger();
await Scheduler.ScheduleJob(job, trigger, cancellationToken);
await Scheduler.Start(cancellationToken);
}
public async Task StopAsync(CancellationToken cancellationToken)
{
await Scheduler?.Shutdown(cancellationToken);
}
private static IJobDetail CreateJob()
{
return JobBuilder
.Create<HelloWorldJob>()
.WithIdentity("_job", "group")
.Build();
}
private static ITrigger CreateTrigger()
{
return TriggerBuilder
.Create()
.WithIdentity("_trigger", "group")
.StartNow()
.WithSimpleSchedule(x => x.WithIntervalInSeconds(5).RepeatForever())
.Build();
}
}
Startup:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
services.AddQuartz(q =>
{
q.UseMicrosoftDependencyInjectionScopedJobFactory();
});
services.AddQuartzHostedService(
quartz => quartz.WaitForJobsToComplete = true);
services.AddSingleton<Quartz.ISchedulerFactory, StdSchedulerFactory>();
services.AddSingleton<HelloWorldJob>();
services.AddHostedService<QuartzHostedService>();
}
HelloWorldJob:
[DisallowConcurrentExecution]
public class HelloWorldJob : IJob
{
private readonly ILogger<HelloWorldJob> _logger;
public HelloWorldJob(ILogger<HelloWorldJob> logger)
{
_logger = logger;
}
public Task Execute(IJobExecutionContext context)
{
_logger.LogInformation("Hello world!");
return Task.CompletedTask;
}
}
Test Result:
Hope this can help you.
Upvotes: 1