Quartz: Why does this Trigger not fire? - quartz.net

I am using quartz.NET in my project. I have the following problem. I want to run a Scheduled task everyday at 23 o'clock and I am using this code to do that:
public class HelloJob : IJob
{
public void Execute(IJobExecutionContext context)
{
//Download file
}
}
public interface ISchedule
{
void Run();
}
public class HelloSchedule : ISchedule
{
public void Run()
{
IJobDetail job = JobBuilder.Create<HelloJob>()
.WithIdentity("job1")
.Build();
ITrigger trigger = TriggerBuilder.Create()
.ForJob(job)
.WithIdentity("trigger1")
.StartNow()
.WithCronSchedule("0 0 23 ? * MON-FRI *")
.Build();
ISchedulerFactory sf = new StdSchedulerFactory();
IScheduler sc = sf.GetScheduler();
sc.ScheduleJob(job, trigger);
sc.Start();
}
}
but unfortunately it's not firing.
How can I know what the problem is and solve it?
Thanks for your advice

Your job will fire at 11pm.
You can check the next fire time for you job using this code:
private static DateTime getNextFireTimeForJob(IScheduler scheduler, string jobName, string groupName = "")
{
JobKey jobKey = null;
if (!string.IsNullOrEmpty(groupName))
{
jobKey = new JobKey(jobName, groupName);
}
else
{
jobKey = new JobKey(jobName);
}
DateTime nextFireTime = DateTime.MinValue;
bool isJobExisting = Scheduler.CheckExists(jobKey);
if (isJobExisting)
{
var detail = scheduler.GetJobDetail(jobKey);
var triggers = scheduler.GetTriggersOfJob(jobKey);
var myTrigger = triggers.Where(f => f.Key.Name == "SecondTrigger").SingleOrDefault();
if (triggers.Count > 0)
{
var nextFireTimeUtc = triggers[0].GetNextFireTimeUtc();
nextFireTime = TimeZone.CurrentTimeZone.ToLocalTime(nextFireTimeUtc.Value.DateTime);
}
}
return (nextFireTime);
}
and get the info using this:
var nextFireTime = getNextFireTimeForJob(sc, "job1");
Make sure your HelloJob implements IJob.
If you're integrating your Quartz.net scheduler in a WinApp make sure it's created singleton cause it might be destroyed when it goes out of scope.
I test my jobs in a console application and use Console.ReadLine(); to wait the jobs execution.

Use org.Quartz and try this:
JobDetail job = new JobDetail();
job.setName(Constants.JOB_NAME);
job.setJobClass(YOUR_JOB_CLASS.class);
CronTrigger trigger = new CronTrigger();
trigger.setName(Constants.TRIGGER_NAME);
trigger.setCronExpression("0 0 23 ? * MON-FRI *");
// schedule it
Scheduler scheduler = new StdSchedulerFactory().getScheduler();
scheduler.start();
scheduler.scheduleJob(job, trigger);
Your Job class should implement org.Quartz.Job interface and override its execute method which does the actual thing the job needs to perform.

Related

Xamarin Android IntentService calling OnDestroy while performing large async operation

Im trying to perform a synchronization task without blocking UI thread. I have implemented a Android Service to do so, but I found out, if the synchronization task needs too much computational time, the UI thread was blocked. So I tried the migration to IntentService. This is how my IntentService looks like:
[Service]
public class SynchronizeIntentService : IntentService
{
static readonly string TAG = typeof(SynchronizeIntentService).FullName;
private NotificationCompat.Builder Builder;
private NotificationManagerCompat NotificationManager;
public SynchronizeIntentService() : base("SynchronizeIntentService")
{
}
public override void OnDestroy()
{
var tmp = 5;
base.OnDestroy();
}
private NotificationChannel createNotificationChannel()
{
var channelId = Constants.NOTIFICATION_CHANNELID;
var channelName = "My Notification Service";
var Channel = new NotificationChannel(channelId, channelName, Android.App.NotificationImportance.Default);
Channel.LightColor = Android.Resource.Color.HoloBlueBright;
Channel.LockscreenVisibility = NotificationVisibility.Public;
return Channel;
}
private void createForegroundService()
{
var mNotificationManager = GetSystemService(Context.NotificationService) as NotificationManager;
if (Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.O)
{
mNotificationManager.CreateNotificationChannel(createNotificationChannel());
}
var notificationBuilder = new NotificationCompat.Builder(this, Constants.NOTIFICATION_CHANNELID);
GenerateNotification();
StartForeground(Constants.SERVICE_RUNNING_NOTIFICATION_ID, Builder.Notification);
}
private void GenerateNotification()
{
NotificationManager = NotificationManagerCompat.From(this);
Builder = new NotificationCompat.Builder(this, Constants.NOTIFICATION_CHANNELID);
Builder.SetContentTitle(ContaScan.Classes.Localize.GetString("Global_SynchProcess", ""))
.SetSmallIcon(Resource.Drawable.icon)
.SetPriority(NotificationCompat.PriorityLow);
}
protected async override void OnHandleIntent(Intent intent)
{
Log.Debug(TAG, "Service Started!");
await Synch();
Log.Debug(TAG, "Service Stopping!");
StopForeground(true);
this.StopSelf();
}
public override StartCommandResult OnStartCommand(Intent intent, [GeneratedEnum] StartCommandFlags flags, int startId)
{
base.OnStartCommand(intent, flags, startId);
createForegroundService();
return StartCommandResult.Sticky;
}
private async Task Synch()
{
//Large synch process
}
}
And this is how the service is getting started:
startServiceIntent = new Intent(Android.App.Application.Context, typeof(SynchronizeIntentService));
startServiceIntent.SetAction(Constants.ACTION_START_SERVICE);
ContextWrapper contextWrapper = new ContextWrapper(Android.App.Application.Context);
contextWrapper.StartService(startServiceIntent);
The problem is OnDestroy() method is called while the Synch() task is being performed and looks like the IntentService is being killed before ending the process.
What am I doing wrong?
First, check your API level. This class was deprecated in API level 30.
And then, when you use the OnHandleIntent, do not call Service.stopSelf().
This method is invoked on the worker thread with a request to process. Only one Intent is processed at a time, but the processing happens on a worker thread that runs independently from other application logic. So, if this code takes a long time, it will hold up other requests to the same IntentService, but it will not hold up anything else. When all requests have been handled, the IntentService stops itself, so you should not call Service.stopSelf().
For more details, please check the link below. https://developer.android.com/reference/android/app/IntentService#onHandleIntent(android.content.Intent)

Having a Quarz.Net Job recurring every 30 minutes... works only the first time

I'm quite new to Quartz.Net (in the past I've set it using Cron sintax to run one time per run).
This time I need to have a recurring task that's performed every 30 minutes.
It performs only one.
Here's what I've done till now
public class Core : ICore
{
private IScheduler scheduler;
private readonly IConfiguration configuration;
private static readonly TimeSpan defaultInterval = new TimeSpan(0,1,0);
public Core(IConfiguration configuration)
{
this.configuration = configuration;
}
public async Task StartAsync()
{
var interval = configuration.GetValue("interval", defaultInterval);
// Grab the Scheduler instance from the Factory
NameValueCollection props = new NameValueCollection
{
{ "quartz.serializer.type", "binary" }
};
StdSchedulerFactory factory = new StdSchedulerFactory(props);
this.scheduler = await factory.GetScheduler();
this.scheduler.JobFactory =new SimpleInjectorJobFactory(ContainerWrapper.Container, Assembly.GetExecutingAssembly());
IJobDetail job = JobBuilder.Create<RinnovoJob>()
.WithIdentity("RinnovoJob", "sender").StoreDurably(true)
.Build();
ITrigger trigger = TriggerBuilder.Create()
.WithIdentity($"trigger_RinnovoJob", "sender")
.StartNow().WithSimpleSchedule(x=>x.WithInterval(interval))
.Build();
// Tell quartz to schedule the job using our trigger
await this.scheduler.ScheduleJob(job, trigger);
// and start it off
await this.scheduler.Start();
}
public void Dispose()
{
}
}
And here's the Job
public class RinnovoJob:IJob
{
[omiss]
public RinnovoJob([omiss])
{
[omiss]
}
public Task Execute(IJobExecutionContext context)
{
log.Info("Passed");
return Task.CompletedTask;
}
}
It writes the "Passed" just one time. I've read on the doc to set the Durability to true, as I've done using StoreDurably(true) but it doesn't seems to work.
Any suggestion?
Another question, is there a way I can avoid the execution of the job if there's one of the same type running?
Thanks in advance
I've managed... I was missing the .RepeatForever() call
Here's the working code
ITrigger trigger = TriggerBuilder.Create()
.WithIdentity($"trigger_RinnovoJob", "sender")
.StartNow().WithSimpleSchedule(x=>x.WithInterval(interval).RepeatForever())
.Build();
Hope this can help others that wasted their time in a similar situation

Quartz.Net multiple User Stations

I'm using Quartz.Net for sending specific emails on specific date/time.
My application has many users.
I'm calling Quartz.Net procedures in program.cs which run at application start.
So, if my users starts the application does it look like it will send the emails multiple times for the same emails? Or will it send only once, no matter how many users starts the application?
Can anyone please explain?
This is my code (basically a sample from Quartz.NET just for testing).
This code is inside program.cs
static class Program
{
[STAThread]
static void Main()
{
try
{
common.logging.logmanager.adapter = new common.logging.simple.consoleoutloggerfactoryadapter { level = common.logging.loglevel.info };
ischeduler scheduler = stdschedulerfactory.getdefaultscheduler();
scheduler.start();
ijobdetail job = jobbuilder.create<hellojob>()
.withidentity("job1", "group1")
.build();
itrigger trigger = triggerbuilder.create()
.withidentity("trigger1", "group1")
.withschedule(cronschedulebuilder.dailyathourandminute(10, 00))
.forjob("job1", "group1")
.build();
scheduler.schedulejob(job, trigger);
thread.sleep(timespan.fromseconds(60));
scheduler.shutdown();
}
catch (schedulerexception se)
{
console.writeline(se);
}
}
}
public class hellojob : ijob
{
public void execute(ijobexecutioncontext context)
{
// do stuff
}
}

How can I call TriggerJob with custom jobDataMap?

I've got a Quartz.NET job which I set up as follows:
var jobKey = new JobKey("JobName", "JobGroup");
var triggerKey = new TriggerKey("JobName", "JobGroup");
var jobData = new JobDataMap();
jobData.Add("SomeKey", "OriginalValue");
var jobDetail = JobBuilder.Create<JobClass>()
.WithIdentity(jobKey)
.StoreDurably()
.UsingJobData(jobData)
.Build();
Scheduler.AddJob(jobDetail, true);
var triggerDetail = TriggerBuilder.Create()
.WithIdentity(triggerKey)
.StartNow()
.WithDailyTimeIntervalSchedule(x => x.OnEveryDay()
.StartingDailyAt(TimeOfDay.HourAndMinuteOfDay(04, 07))
.EndingDailyAt(TimeOfDay.HourAndMinuteOfDay(06, 07))
.WithMisfireHandlingInstructionFireAndProceed())
.ForJob(jobKey)
.Build();
Scheduler.ScheduleJob(triggerDetail);
I am trying to manually trigger that job using the following code:
var jobData = new JobDataMap();
jobData.Add("SomeKey", "SomeValue");
TaskScheduler.Scheduler.TriggerJob(new Quartz.JobKey("JobName", "JobGroup"), jobData);
When I run the manual trigger this piece of code, the value in
context.JobDetail.JobDataMap["SomeKey"]
is
"OriginalValue"
rather than
"SomeValue"
as I would expect. What am I doing wrong?
Both trigger and job have jobData.
Line TaskScheduler.Scheduler.TriggerJob(new Quartz.JobKey("JobName", "JobGroup"), jobData);
assigns jobData to trigger. You can see 'SomeValue' in context.Trigger.JobDataMap["SomeKey"]
Using a reference type works:
//A simple class used here only for storing a string value:
public class SimpleDTO
{
public string Value { get; set; }
}
void Work() {
var dto = new SimpleDTO();
dto.Value = "OriginalValue";
JobDataMap data = new JobDataMap();
data["Key"] = dto;
TaskScheduler.Scheduler.TriggerJob(new Quartz.JobKey("JobName", "JobGroup"), jobData);
//read modified new value:
var resultDto = (SimpleDTO)data["Key"];
Assert.AreEqual("NewValue", resultDto.Value);
}
public void Execute(IJobExecutionContext context)
{
var simpleDTO = (SimpleDTO)context.MergedJobDataMap["SomeKey"];
//set a new value:
simpleDTO.Value = "NewValue";
}

Problem Running SSIS Package from Windows Service

I created a Windows Service that executes a SSIS Package every five minutes. It works pretty well, but something is tripping it up.
Every week the server restarts, and after the restart, the Service stops working. Events for the SSIS Package beginning/ending executions still appear in the event viewer, but the package doesn't work as it should. When I manually start/stop the service, all works as normal again.
Am I missing something that I should be doing with the Pacakge?
I use a web service to get the location of the SSIS Package. I stripped most of that out of the code below, but left enough of it that the structure of my service is maintained.
Here is the jist of my code:
namespace MyService
{
partial class MyService : ServiceBase
{
private Timer timer;
private Package pkg;
bool executing;
public MyService()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
executing = false;
TimerCallback callback = new TimerCallback(Init);
int period = 1000 * 60; //attempt to initialize every minute.
timer = new Timer(callback, null, 0, period);
}
private void Init(object state)
{
try
{
//Get `timeIntervalMinutes` from Parameters table
string mySQLStatement = "...";
DataSet ds = mySQLQuery(...);
int timeIntervalMinutes = Convert.ToInt32(ds.Tables["timeIntervalMinutes"].Rows[0]["Value"]);
//Get `path` from Parameters table
string mySQLStatement = "...";
DataSet ds = mySQLQuery(...);
string path = Convert.ToString(ds.Tables["path"].Rows[0]["Value"]);
//Get `path` from Parameters table
string mySQLStatement = "...";
DataSet ds = mySQLQuery(...);
string server = Convert.ToString(ds.Tables["server"].Rows[0]["Value"]);
//Load the SSIS Package
Application app = new Application();
pkg = app.LoadFromDtsServer(path, server, null);
//If this line is reached, a connection to MyWS has been made, so switch the timer to run the SSIS package
timer.Dispose();
TimerCallback callback = new TimerCallback(OnTimedEvent);
int period = 1000 * 60 * timeIntervalMinutes;
timer = new Timer(callback, null, 0, period);
}
catch (Exception e)
{
return;
}
}
private void OnTimedEvent(object state)
{
if (!executing)
{
executing = true;
DTSExecResult pkgResults = pkg.Execute();
executing = false;
}
}
protected override void OnStop()
{
}
//<MyWS is here>
}
}
Thanks for the help!
Your service or process maybe dependent on another service - say MSDTC. IF this service is not ready as quickly after startup you could get unpredictable results. Either delay the startup of your service or figure out the dependency and set is in the service properties

Resources