basquang™ on clouds

August 7, 2014

[Quartz.NET]: Configure AdoJobStore JobStore

Filed under: Quartz,Quartz.NET — basquang @ 4:05 PM
Tags: ,

JobStore‘s are responsible for keeping track of all the “work data” that you give to the scheduler: jobs, triggers, calendars, etc.

RAMJobStore

RAMJobStore is the simplest JobStore to use, it is also the most performant (in terms of CPU time). RAMJobStore gets its name in the obvious way: it keeps all of its data in RAM. This is why it’s lightning-fast, and also why it’s so simple to configure. The drawback is that when your application ends (or crashes) all of the scheduling information is lost – this means RAMJobStore cannot honor the setting of “non-volatility” on jobs and triggers. For some applications this is acceptable – or even the desired behavior, but for other applications, this may be disasterous.

Configuring Quartz to use RAMJobStore

quartz.jobStore.type = Quartz.Simpl.RAMJobStore, Quartz

To use RAMJobStore (and assuming you’re using StdSchedulerFactory) you don’t need to do anything special. Default configuration of Quartz.NET uses RAMJobStore as job store implementation.

ADO.NET Job Store (AdoJobStore)

AdoJobStore is also aptly named – it keeps all of its data in a database via ADO.NET. Because of this it is a bit more complicated to configure than RAMJobStore, and it also is not as fast. However, the performance draw-back is not terribly bad, especially if you build the database tables with indexes on the primary keys.

To use AdoJobStore, you must first create a set of database tables for Quartz.NET to use. You can find table-creation SQL scripts in the “database/dbtables” directory of the Quartz.NET distribution. If there is not already a script for your database type, just look at one of the existing ones, and modify it in any way necessary for your DB. One thing to note is that in these scripts, all the the tables start with the prefix “QRTZ_” such as the tables “QRTZ_TRIGGERS”, and “QRTZ_JOB_DETAIL”). This prefix can actually be anything you’d like, as long as you inform AdoJobStore what the prefix is (in your Quartz.NET properties). Using different prefixes may be useful for creating multiple sets of tables, for multiple scheduler instances, within the same database.

This article describe simple steps to configure ADO.NET Job Store

  1. Download Quartz.NET package from here http://sourceforge.net/projects/quartznet/files/quartznet/
  2. Run the SQL file tables_sqlServer.sql to create ADO.NET Quartz Job Store tables. After complete you will see list of tables as picture below

     

  3. Create Console Application
  4. Install Quartz.NET NuGet package
  5. Configure logging in App.config as code below

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
    
      <configSections>
        <!--<section name="quartz" type="System.Configuration.NameValueSectionHandler, System, Version=1.0.5000.0,Culture=neutral, PublicKeyToken=b77a5c561934e089" />-->
        <sectionGroup name="common">
          <section name="logging" type="Common.Logging.ConfigurationSectionHandler, Common.Logging"/>
        </sectionGroup>
      </configSections>
    
      <common>
        <logging>
          <factoryAdapter type="Common.Logging.Simple.ConsoleOutLoggerFactoryAdapter, Common.Logging">
            <arg key="showLogName" value="true"/>
            <arg key="showDataTime" value="true"/>
            <arg key="level" value="INFO"/>
            <arg key="dateTimeFormat" value="HH:mm:ss:fff"/>
          </factoryAdapter>
        </logging>
      </common>
    
      <connectionStrings>
        <add name="QuartzStore" connectionString="Data Source=QUANGNB;Initial Catalog=QuartzNETStore;User ID=sa;Password=********" providerName="System.Data.SqlClient" />
      </connectionStrings>
    
      <!-- 
        We use quartz.config for this server, you can always use configuration section if you want to.
        Configuration section has precedence here.  
      -->
      <!--
      <quartz >
      </quartz>
      -->
    
      <startup>
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
      </startup>
    </configuration>
    

  6. Create quartz.config file and set Build Action = None, Copy to Output Directory = Copy Always. Then add following code to configure Quartz.NET to use ADO Job Store

    # You can configure your scheduler in either <quartz> configuration section
    # or in quartz properties file
    # Configuration section has precedence
    
    quartz.scheduler.instanceName = MyScheduler
    quartz.scheduler.instanceId = AUTO
    quartz.threadPool.type = Quartz.Simpl.SimpleThreadPool, Quartz 
    
    # this section configures the scheduler to use sqlite as the jobstore
    # to use the RAM store just comment all of this out
    # to use the sqlite store, uncomment all of this 
    quartz.jobStore.type = Quartz.Impl.AdoJobStore.JobStoreTX, Quartz 
    quartz.jobStore.dataSource = default 
    quartz.jobStore.tablePrefix = QRTZ_ 
    quartz.jobStore.clustered = false
    quartz.jobStore.lockHandler.type = Quartz.Impl.AdoJobStore.SimpleSemaphore, Quartz 
    quartz.jobStore.driverDelegateType = Quartz.Impl.AdoJobStore.StdAdoDelegate, Quartz 
    quartz.dataSource.default.provider = SqlServer-20
    quartz.jobStore.useProperties = true
    quartz.jobStore.selectWithLockSQL = SELECT * FROM {0} LOCKS UPDLOCK WHERE LOCK_NAME = @ lockName
    quartz.dataSource.default.connectionStringName = QuartzStore
    quartz.dataSource.default.connectionString = Data Source=QUANGNB;Initial Catalog=QuartzNETStore;User ID=sa;Password=******
    
    # this section configures the scheduler to use sql server ce as the jobstore
    #quartz.jobStore.type = Quartz.Impl.AdoJobStore.JobStoreTX, Quartz 
    #quartz.jobStore.dataSource = default 
    #quartz.dataSource.default.connectionString = Data Source=quartz.sdf;Persist Security Info=False;
    #quartz.jobStore.tablePrefix = QRTZ_ 
    #quartz.jobStore.clustered = false
    #quartz.jobStore.lockHandler.type = Quartz.Impl.AdoJobStore.UpdateLockRowSemaphore, Quartz 
    #quartz.jobStore.driverDelegateType = Quartz.Impl.AdoJobStore.SqlServerDelegate, Quartz 
    #quartz.dataSource.default.provider = SqlServerCe-351
    #quartz.jobStore.useProperties = true
    

  7. Create Simple Job like this

    public class SimpleJob : IJob
        {
            private static ILog logging = LogManager.GetLogger(typeof(SimpleJob));
    
            public void Execute(IJobExecutionContext context)
            {
                logging.InfoFormat("Hello from job");
            }
        }
    

  8. Using the Job in Program like this

    ILog log = LogManager.GetLogger(typeof(Program));           
    
    // First we must get a reference to a scheduler
    ISchedulerFactory sf = new StdSchedulerFactory();
    IScheduler sched = sf.GetScheduler();
    
    try
    {
    	var startTime = DateTimeOffset.Now.AddSeconds(5);
    
    	var job = JobBuilder.Create<SimpleJob>()
    						.WithIdentity("job1", "group1")
    						.Build();
    
    	var trigger = TriggerBuilder.Create()
    		.WithIdentity("trigger1", "group1")
    		.StartAt(startTime)
    		.WithSimpleSchedule(x => x.WithIntervalInSeconds(10).RepeatForever())
    		.Build();
    
    	sched.ScheduleJob(job, trigger);       
    
    	sched.Start();
    	Thread.Sleep(TimeSpan.FromMinutes(2));
    }
    finally
    {
    	sched.Shutdown(true);
    }         
    

  9. Now run for testing ADO Job Store. The Output like this

    15:56:31:280 [INFO]  Quartz.Impl.StdSchedulerFactory - Quartz.NET properties loa
    ded from configuration file 'C:\Users\Quang\Documents\Visual Studio 2013\Project
    s\QuartzNETSolution\Lesson6\bin\Debug\quartz.config'
    15:56:31:372 [INFO]  Quartz.Util.DBConnectionManager - Registering datasource 'd
    efault' with db provider: 'Quartz.Impl.AdoJobStore.Common.DbProvider'
    15:56:31:372 [INFO]  Quartz.Impl.StdSchedulerFactory - Using default implementat
    ion for object serializer
    15:56:31:383 [INFO]  Quartz.Impl.StdSchedulerFactory - Using custom data access
    locking (synchronization): Quartz.Impl.AdoJobStore.SimpleSemaphore
    15:56:31:384 [INFO]  Quartz.Impl.StdSchedulerFactory - Using default implementat
    ion for ThreadExecutor
    15:56:31:460 [INFO]  Quartz.Core.SchedulerSignalerImpl - Initialized Scheduler S
    ignaller of type: Quartz.Core.SchedulerSignalerImpl
    15:56:31:461 [INFO]  Quartz.Core.QuartzScheduler - Quartz Scheduler v.2.2.4.400
    created.
    15:56:31:491 [WARN]  Quartz.Impl.AdoJobStore.JobStoreTX - Detected usage of SQL
    Server provider without SqlServerDelegate, SqlServerDelegate would provide bette
    r performance
    15:56:31:491 [INFO]  Quartz.Impl.AdoJobStore.JobStoreTX - JobStoreTX initialized
    .
    15:56:31:498 [INFO]  Quartz.Core.QuartzScheduler - Scheduler meta-data: Quartz S
    cheduler (v2.2.4.400) 'MyScheduler' with instanceId 'NON_CLUSTERED'
      Scheduler class: 'Quartz.Core.QuartzScheduler' - running locally.
      NOT STARTED.
      Currently in standby mode.
      Number of jobs executed: 0
      Using thread pool 'Quartz.Simpl.SimpleThreadPool' - with 10 threads.
      Using job-store 'Quartz.Impl.AdoJobStore.JobStoreTX' - which supports persiste
    nce. and is not clustered.
    
    15:56:31:500 [INFO]  Quartz.Impl.StdSchedulerFactory - Quartz scheduler 'MySched
    uler' initialized
    15:56:31:501 [INFO]  Quartz.Impl.StdSchedulerFactory - Quartz scheduler version:
     2.2.4.400
    15:56:31:800 [INFO]  Quartz.Impl.AdoJobStore.JobStoreTX - Freed 0 triggers from
    'acquired' / 'blocked' state.
    15:56:31:844 [INFO]  Quartz.Impl.AdoJobStore.JobStoreTX - Recovering 0 jobs that
     were in-progress at the time of the last shut-down.
    15:56:31:844 [INFO]  Quartz.Impl.AdoJobStore.JobStoreTX - Recovery complete.
    15:56:31:861 [INFO]  Quartz.Impl.AdoJobStore.JobStoreTX - Removed 0 'complete' t
    riggers.
    15:56:31:876 [INFO]  Quartz.Impl.AdoJobStore.JobStoreTX - Removed 0 stale fired
    job entries.
    15:56:31:888 [INFO]  Quartz.Core.QuartzScheduler - Scheduler MyScheduler_$_NON_C
    LUSTERED started.
    15:56:36:787 [INFO]  Lesson6.SimpleJob - Hello from job
    15:56:46:619 [INFO]  Lesson6.SimpleJob - Hello from job
    ...
    

     

    While program running Open QRTZ_FIRED_TRIGGERS table

     

    While program running Open QRTZ_JOB_DETAILS table

     

    While program running Open QRTZ_TRIGGERS table

     

    Hope this help!

August 6, 2014

[Quartz.NET]: Configure Job in XML using Quartz plug-in XMLSchedulingDataProcessorPlugin

Filed under: Quartz,Quartz.NET — basquang @ 2:57 PM
Tags: ,

You can initialize the scheduler with predefined jobs and triggers using the XMLSchedulingDataProcessorPlugin. This plugin loads XML file(s) to add jobs and schedule them with triggers as the scheduler is initialized, and can optionally periodically scan the file for changes.The XML schema definition can be found here: http://www.quartz-scheduler.org/xml/job_scheduling_data_2_0.xsd

Here are simple steps to use Quartz.NET plugin

  1. Create Console Application
  2. Install Quartz.NET from NuGet
  3. Add logging configuration in App.config as below

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
    
      <configSections>
        <sectionGroup name="common">
          <section name="logging" type="Common.Logging.ConfigurationSectionHandler, Common.Logging"/>
        </sectionGroup>
      </configSections>
    
      <common>
        <logging>
          <factoryAdapter type="Common.Logging.Simple.ConsoleOutLoggerFactoryAdapter, Common.Logging">
            <arg key="showLogName" value="true"/>
            <arg key="showDataTime" value="true"/>
            <arg key="level" value="INFO"/>
            <arg key="dateTimeFormat" value="HH:mm:ss:fff"/>
          </factoryAdapter>
        </logging>
      </common>
      
        <startup> 
            <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
        </startup>
    </configuration>
    

  4. Create a simple job as code below

    namespace Lesson5
    {
        public class SimpleJob : IJob
        {
            private static readonly ILog log = LogManager.GetLogger(typeof(SimpleJob));
    
            /// <summary>
            /// Called by the <see cref="IScheduler" /> when a
            /// <see cref="ITrigger" /> fires that is associated with
            /// the <see cref="IJob" />.
            /// </summary>
            public virtual void Execute(IJobExecutionContext context)
            {
                // This job simply prints out its job name and the
                // date and time that it is running
                JobKey jobKey = context.JobDetail.Key;
                log.InfoFormat("Executing job: {0} executing at {1}", jobKey, DateTime.Now.ToString("r"));
    
    
                if (context.MergedJobDataMap.Count > 0)
                {
                    ICollection<string> keys = context.MergedJobDataMap.Keys;
                    foreach (string key in keys)
                    {
                        String val = context.MergedJobDataMap.GetString(key);
                        log.InfoFormat(" - jobDataMap entry: {0} = {1}", key, val);
                    }
                }
    
                context.Result = "hello";
            }
        }
    }
    

  5. Create a xml file named as quartz_jobs.xml and set Build Action=Content and Copy to Output Directory=Copy always as below

    <?xml version="1.0" encoding="utf-8" ?>
    <job-scheduling-data xmlns="http://quartznet.sourceforge.net/JobSchedulingData"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     				version="2.0">
    
      <processing-directives>
        <overwrite-existing-data>true</overwrite-existing-data>
      </processing-directives>
    
      <schedule>
    
        <job>
          <name>jobName1</name>
          <group>jobGroup1</group>
          <description>jobDesciption1</description>
          <job-type>Lesson5.SimpleJob, Lesson5</job-type>
          <durable>true</durable>
          <recover>false</recover>
          <job-data-map>
            <entry>
              <key>key0</key>
              <value>value0</value>
            </entry>
            <entry>
              <key>key1</key>
              <value>value1</value>
            </entry>
            <entry>
              <key>key2</key>
              <value>value2</value>
            </entry>
          </job-data-map>
        </job>
    
        <trigger>
          <simple>
            <name>simpleName</name>
            <group>simpleGroup</group>
            <description>SimpleTriggerDescription</description>
            <job-name>jobName1</job-name>
            <job-group>jobGroup1</job-group>
            <start-time>1982-06-28T18:15:00.0Z</start-time>
            <end-time>2020-05-04T18:13:51.0Z</end-time>
            <misfire-instruction>SmartPolicy</misfire-instruction>
            <repeat-count>100</repeat-count>
            <repeat-interval>3000</repeat-interval>
          </simple>
        </trigger>
    
      </schedule>
    
    </job-scheduling-data>
    

  6. Loading the job in XML plugin in Program console as code below

    ILog log = LogManager.GetLogger(typeof(Program));
    
    // our properties that enable XML configuration plugin
    // and makes it watch for changes every two minutes (120 seconds)
    var properties = new NameValueCollection();
    properties["quartz.plugin.triggHistory.type"] = "Quartz.Plugin.History.LoggingJobHistoryPlugin";
    
    properties["quartz.plugin.jobInitializer.type"] = "Quartz.Plugin.Xml.XMLSchedulingDataProcessorPlugin";
    properties["quartz.plugin.jobInitializer.fileNames"] = "quartz_jobs.xml";
    properties["quartz.plugin.jobInitializer.failOnFileNotFound"] = "true";
    properties["quartz.plugin.jobInitializer.scanInterval"] = "120";
    
    // First we must get a reference to a scheduler
    ISchedulerFactory sf = new StdSchedulerFactory(properties);
    IScheduler sched = sf.GetScheduler();
    
    // start the schedule 
    sched.Start();
    
    // wait five minutes to give our jobs a chance to run
    try
    {
    	Thread.Sleep(TimeSpan.FromMinutes(5));
    }
    catch (ThreadInterruptedException)
    {
    }
    
    // shut down the scheduler
    sched.Shutdown(true);      
    

Hope this help!

[Quartz.NET]: JobDataMap

Filed under: Quartz,Quartz.NET — basquang @ 2:33 PM
Tags: ,

What is JobDataMap?

The JobDataMap can be used to hold any number of (serializable) objects which you wish to have made available to the job instance when it executes. JobDataMap is an implementation of the IDictionary interface, and has some added convenience methods for storing and retrieving data of primitive types.

In my opinion, JobDataMap used to passing data between Quartz.NET host and Job instance?

Here is one sample code describes how to use JobDataMap.

  1. Create Console Application
  2. Install Quartz.NET from NuGet package
  3. Add logging configuration to App.config as below

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
    
      <configSections>
        <sectionGroup name="common">
          <section name="logging" type="Common.Logging.ConfigurationSectionHandler, Common.Logging"/>
        </sectionGroup>
      </configSections>
    
      <common>
        <logging>
          <factoryAdapter type="Common.Logging.Simple.ConsoleOutLoggerFactoryAdapter, Common.Logging">
            <arg key="showLogName" value="true"/>
            <arg key="showDataTime" value="true"/>
            <arg key="level" value="INFO"/>
            <arg key="dateTimeFormat" value="HH:mm:ss:fff"/>
          </factoryAdapter>
        </logging>
      </common>
      
        <startup> 
            <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
        </startup>
    </configuration>
    

  4. Define simple ColorJob as code below. This job simple reads data from JobDataMap and write to log

    [PersistJobDataAfterExecution]
    [DisallowConcurrentExecution]
    public class ColorJob : IJob
    {
    	private static readonly ILog log = LogManager.GetLogger(typeof(ColorJob));
    
    	// parameter names specific to this job
    	public const string FavoriteColor = "favorite color";
    	public const string ExecutionCount = "count";
    
    	// Since Quartz will re-instantiate a class every time it
    	// gets executed, members non-static member variables can
    	// not be used to maintain state!
    	private int counter = 1;
    
    	/// <summary>
    	/// Called by the <see cref="IScheduler" /> when a
    	/// <see cref="ITrigger" /> fires that is associated with
    	/// the <see cref="IJob" />.
    	/// </summary>
    	public virtual void Execute(IJobExecutionContext context)
    	{
    
    		// This job simply prints out its job name and the
    		// date and time that it is running
    		JobKey jobKey = context.JobDetail.Key;
    
    		// Grab and print passed parameters
    		JobDataMap data = context.JobDetail.JobDataMap;
    		string favoriteColor = data.GetString(FavoriteColor);
    		int count = data.GetInt(ExecutionCount);
    		log.InfoFormat(
    			"ColorJob: {0} executing at {1}\n  favorite color is {2}\n  execution count (from job map) is {3}\n  execution count (from job member variable) is {4}",
    			jobKey,
    			DateTime.Now.ToString("r"),
    			favoriteColor,
    			count, counter);
    
    		// increment the count and store it back into the 
    		// job map so that job state can be properly maintained
    		count++;
    		data.Put(ExecutionCount, count);
    
    		// Increment the local member variable 
    		// This serves no real purpose since job state can not 
    		// be maintained via member variables!
    		counter++;
    	}
    
    }
    

  5. Using the job in Program as code below:

    ILog log = LogManager.GetLogger(typeof(Program));
    
    // First we must get a reference to a scheduler
    ISchedulerFactory sf = new StdSchedulerFactory();
    IScheduler sched = sf.GetScheduler();
    
    // get a "nice round" time a few seconds in the future....
    DateTimeOffset startTime = DateBuilder.NextGivenSecondDate(null, 10);
    
    // job1 will only run 5 times (at start time, plus 4 repeats), every 10 seconds
    IJobDetail job1 = JobBuilder.Create<ColorJob>()
    	.WithIdentity("job1", "group1")
    	.Build();
    
    ISimpleTrigger trigger1 = (ISimpleTrigger)TriggerBuilder.Create()
    											   .WithIdentity("trigger1", "group1")
    											   .StartAt(startTime)
    											   .WithSimpleSchedule(x => x.WithIntervalInSeconds(10).WithRepeatCount(4))
    											   .Build();
    
    // pass initialization parameters into the job
    job1.JobDataMap.Put(ColorJob.FavoriteColor, "Green");
    job1.JobDataMap.Put(ColorJob.ExecutionCount, 1);
    
    // schedule the job to run
    DateTimeOffset scheduleTime1 = sched.ScheduleJob(job1, trigger1);
    log.Info(string.Format("{0} will run at: {1} and repeat: {2} times, every {3} seconds", 
    	job1.Key, 
    	scheduleTime1.ToString("r"), 
    	trigger1.RepeatCount, 
    	trigger1.RepeatInterval.TotalSeconds));           
    
    // All of the jobs have been added to the scheduler, but none of the jobs
    // will run until the scheduler has been started
    sched.Start();
    
    log.Info("------- Waiting 60 seconds... -------------");
    try
    {
    	// wait five minutes to show jobs
    	Thread.Sleep(300 * 1000);
    	// executing...
    }
    catch (ThreadInterruptedException)
    {
    }
    
    sched.Shutdown(true);          
    

  6. The output similar like this

    14:29:20:014 [INFO]  Quartz.Impl.StdSchedulerFactory - Default Quartz.NET proper
    ties loaded from embedded resource file
    14:29:20:112 [INFO]  Quartz.Impl.StdSchedulerFactory - Using default implementat
    ion for object serializer
    14:29:20:174 [INFO]  Quartz.Impl.StdSchedulerFactory - Using default implementat
    ion for ThreadExecutor
    14:29:20:202 [INFO]  Quartz.Core.SchedulerSignalerImpl - Initialized Scheduler S
    ignaller of type: Quartz.Core.SchedulerSignalerImpl
    14:29:20:203 [INFO]  Quartz.Core.QuartzScheduler - Quartz Scheduler v.2.2.4.400
    created.
    14:29:20:206 [INFO]  Quartz.Simpl.RAMJobStore - RAMJobStore initialized.
    14:29:20:212 [INFO]  Quartz.Core.QuartzScheduler - Scheduler meta-data: Quartz S
    cheduler (v2.2.4.400) 'DefaultQuartzScheduler' with instanceId 'NON_CLUSTERED'
      Scheduler class: 'Quartz.Core.QuartzScheduler' - running locally.
      NOT STARTED.
      Currently in standby mode.
      Number of jobs executed: 0
      Using thread pool 'Quartz.Simpl.SimpleThreadPool' - with 10 threads.
      Using job-store 'Quartz.Simpl.RAMJobStore' - which does not support persistenc
    e. and is not clustered.
    
    14:29:20:213 [INFO]  Quartz.Impl.StdSchedulerFactory - Quartz scheduler 'Default
    QuartzScheduler' initialized
    14:29:20:213 [INFO]  Quartz.Impl.StdSchedulerFactory - Quartz scheduler version:
     2.2.4.400
    14:29:20:260 [INFO]  Lesson4.Program - group1.job1 will run at: Wed, 06 Aug 2014
     07:29:30 GMT and repeat: 4 times, every 10 seconds
    14:29:20:264 [INFO]  Quartz.Core.QuartzScheduler - Scheduler DefaultQuartzSchedu
    ler_$_NON_CLUSTERED started.
    14:29:20:266 [INFO]  Lesson4.Program - ------- Waiting 60 seconds... -----------
    --
    14:29:30:111 [INFO]  Lesson4.ColorJob - ColorJob: group1.job1 executing at Wed,
    06 Aug 2014 14:29:30 GMT
      favorite color is Green
      execution count (from job map) is 1
      execution count (from job member variable) is 1
    14:29:39:999 [INFO]  Lesson4.ColorJob - ColorJob: group1.job1 executing at Wed,
    06 Aug 2014 14:29:39 GMT
      favorite color is Green
      execution count (from job map) is 2
      execution count (from job member variable) is 1
    14:29:49:999 [INFO]  Lesson4.ColorJob - ColorJob: group1.job1 executing at Wed,
    06 Aug 2014 14:29:49 GMT
      favorite color is Green
      execution count (from job map) is 3
      execution count (from job member variable) is 1
    14:29:59:999 [INFO]  Lesson4.ColorJob - ColorJob: group1.job1 executing at Wed,
    06 Aug 2014 14:29:59 GMT
      favorite color is Green
      execution count (from job map) is 4
      execution count (from job member variable) is 1
    14:30:09:999 [INFO]  Lesson4.ColorJob - ColorJob: group1.job1 executing at Wed,
    06 Aug 2014 14:30:09 GMT
      favorite color is Green
      execution count (from job map) is 5
      execution count (from job member variable) is 1
    14:34:20:252 [INFO]  Quartz.Core.QuartzScheduler - Scheduler DefaultQuartzSchedu
    ler_$_NON_CLUSTERED shutting down.
    14:34:20:257 [INFO]  Quartz.Core.QuartzScheduler - Scheduler DefaultQuartzSchedu
    ler_$_NON_CLUSTERED paused.
    14:34:20:653 [INFO]  Quartz.Core.QuartzScheduler - Scheduler DefaultQuartzSchedu
    ler_$_NON_CLUSTERED Shutdown complete.
    Press any key to continue . . .
    

Hope this help!

August 4, 2014

[Quartz.NET]: Configure NLog for logging

Filed under: Logging,Quartz,Quartz.NET — basquang @ 5:47 PM
Tags: ,

In previous article Configure Logging I described how to configure Logging in configuration file using Common.Logging.Simple.ConsoleOutLoggerFactoryAdapter.

In this article, I will describe how to configure NLog in Quartz application.

Because Quartz.NET using Common.Logging frameworks, so there are two implementations dependency when you want to use NLogLoggerFactoryAdapter:

  • Common.Logging.NLog20 is linked against NLog 2.0.0.2
  • Common.Logging.NLog10 is linked against NLog 1.0.0.505

So you need to install correct version of Common.Logging.NLog and NLog.

  1. Create Console Application
  2. Install Quartz.NET from NutGet. By default at this time NuGet will install following packages. By default Quartz use Common.Logging v2.1.2

    <packages>
      <package id="Common.Logging" version="2.1.2" targetFramework="net45" />
      <package id="Quartz" version="2.2.4" targetFramework="net45" />
    </packages>
    

  3. Add the configuration code below to configure NLog in the App.config file

    <?xml version="1.0" encoding="utf-8"?>
    <configuration>
    
      <configSections>
        <sectionGroup name="common">
          <section name="logging" type="Common.Logging.ConfigurationSectionHandler, Common.Logging" />
        </sectionGroup>
        <section name="nlog" type="NLog.Config.ConfigSectionHandler, NLog" />
      </configSections>
    
      <common>
        <logging>
          <factoryAdapter type="Common.Logging.NLog.NLogLoggerFactoryAdapter, Common.Logging.NLog20">
            <arg key="configType" value="INLINE" />
          </factoryAdapter>
        </logging>
      </common>
    
      <nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
        <targets>
          <target name="file" xsi:type="File" layout="${date:format=HH\:MM\:ss} ${logger} ${message}" fileName="${basedir}/logs/logfile.txt" />
        </targets>
        <rules>
          <logger name="*" minlevel="Debug" writeTo="file" />
        </rules>
      </nlog>
    
      <startup>
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
      </startup>       
    </configuration>
    

  4. Create simple Job like this

    public class SimpleJob : IJob
        {
            private static ILog logging = LogManager.GetLogger(typeof(SimpleJob));
    
            public void Execute(IJobExecutionContext context)
            {
                logging.InfoFormat("Hello from job");
            }
        }
    

  5. Using the job in Program

    ILog log = LogManager.GetLogger(typeof(Program));
    
    // First we must get a reference to a scheduler
    ISchedulerFactory sf = new StdSchedulerFactory();
    IScheduler sched = sf.GetScheduler();
    
    //////////////////
    try
    {
    	var startTime = DateTimeOffset.Now.AddSeconds(5);
    
    	var job = JobBuilder.Create<SimpleJob>()
    						.WithIdentity("job1", "group1")
    						.Build();
    
    	var trigger = TriggerBuilder.Create()
    		.WithIdentity("trigger1", "group1")
    		.StartAt(startTime)
    		.WithSimpleSchedule(x => x.WithIntervalInSeconds(10).WithRepeatCount(4))
    		.Build();
    
    	sched.ScheduleJob(job, trigger);       
    
    	sched.Start();
    	Thread.Sleep(TimeSpan.FromSeconds(30));
    }
    finally
    {
    	sched.Shutdown(true);
    }
    

  6. When press F5 to run the application following error will appear

    Unable to create type ‘Common.Logging.NLog.NLogLoggerFactoryAdapter, Common.Logging.NLog20’

  7. To resolve this issue. Install Common.Logging.NLog20 from NuGet by running following command in order.NOTE: To use NLong we need to update Common.Logging to version 2.2.0

    Install-Package Common.Logging.NLog20

    Install-Package Common.Logging.Core

    Install-Package Common.Logging -Version 2.2.0

    This command will install following packages

    <packages>
      <package id="Common.Logging" version="2.2.0" targetFramework="net45" />
      <package id="Common.Logging.Core" version="2.2.0" targetFramework="net45" />
      <package id="Common.Logging.NLog20" version="2.2.0" targetFramework="net45" />
      <package id="NLog" version="2.0.0.2000" targetFramework="net45" />
      <package id="Quartz" version="2.2.4" targetFramework="net45" />
    </packages>
    

  8. Now run application again and see the output of logged file in the path bin\debug\logs\logfile.txt

The logged file created by NLog in the configuration you have defined above.

Hope this help!

 

[Quartz.NET]: Configure Logging

Filed under: Logging,Quartz,Quartz.NET — basquang @ 5:02 PM
Tags: ,

Common.Logging can be configured to use different logging frameworks under the hood; namely Enterprise Library, Log4Net and NLog.

However, to keep things simple in last post Get Started we take the simple route and configure logging using code to just log to the console using Common.Logging basic logging mechanism.

Common.Logging.LogManager.Adapter = new Common.Logging.Simple.ConsoleOutLoggerFactoryAdapter { Level = Common.Logging.LogLevel.Info};

This blog post describe how to configure Logging in application configuration file.

  1. Create Console Application
  2. Install Quartz.NET from NuGet
  3. Add following code in the App.config to configure Logging for Quart. In this logging configuration we use ConsoleOutLoggerFactoryAdapter to display log to the Console.Out screen.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  
  <configSections>   
    <sectionGroup name="common">
      <section name="logging" type="Common.Logging.ConfigurationSectionHandler, Common.Logging"/>
    </sectionGroup>
  </configSections>

  <common>
    <logging>
      <factoryAdapter type="Common.Logging.Simple.ConsoleOutLoggerFactoryAdapter, Common.Logging">
        <arg key="showLogName" value="true"/>
        <arg key="showDataTime" value="true"/>
        <arg key="level" value="INFO"/>
        <arg key="dateTimeFormat" value="HH:mm:ss:fff"/>
      </factoryAdapter>
    </logging>
  </common>
  
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
    </startup>
</configuration>

  1. Add a simple Job like this. In this Job we use log the execution of the Job by writing the message “Hello World…”

    public class HelloJob : IJob
        {
            //Get logging configuration
            private static ILog _log = LogManager.GetLogger(typeof(HelloJob));
    
            /// <summary> 
            /// Called by the <see cref="IScheduler" /> when a
            /// <see cref="ITrigger" /> fires that is associated with
            /// the <see cref="IJob" />.
            /// </summary>
            public virtual void Execute(IJobExecutionContext context)
            {
    
                // Say Hello to the World and display the date/time
                _log.Info(string.Format("Hello World! - {0}", System.DateTime.Now.ToString()));
            }
    
        }
    

  2. Using the Job in Program class as below
  3. //Get Logging configuration
    ILog log = LogManager.GetLogger(typeof(Program));
    
    // First we must get a reference to a scheduler
    ISchedulerFactory sf = new StdSchedulerFactory();
    IScheduler sched = sf.GetScheduler();
    
    log.Info("------- Scheduling Job  -------------------");
    
    // define the job and tie it to our HelloJob class
    IJobDetail job = JobBuilder.Create<HelloJob>()
    	.WithIdentity("job1", "group1")
    	.Build();
    
    // Trigger the job to run on the next round minute
    ITrigger trigger = TriggerBuilder.Create()
    	.WithIdentity("trigger1", "group1")
    	.StartNow()
    	.WithSimpleSchedule(x => x
    	.WithIntervalInSeconds(10)
    	.RepeatForever())
    	.Build();
    
    // Tell quartz to schedule the job using our trigger
    sched.ScheduleJob(job, trigger);           
    
    // Start up the scheduler (nothing can actually run until the 
    // scheduler has been started)
    sched.Start();
    
    // wait long enough so that the scheduler as an opportunity to 
    // run the job!
    
    // wait 65 seconds to show jobs
    Thread.Sleep(TimeSpan.FromSeconds(60));
    
    // shut down the scheduler
    sched.Shutdown(true);
    

  4. The Console screen output will display the message (execute the job) you have been defined each 10 seconds 6 time (within 60 seconds)

Hope this help

[Quartz.NET]: Get Started

Filed under: Quartz,Quartz.NET — basquang @ 4:32 PM
Tags: ,

What is Quartz.NET?

“Quartz.NET is a full-featured, open source job scheduling system that can be used from smallest apps to large scale enterprise systems. ”

Quartz.NET is a pure .NET library written in C# and is a port of very popular open source Java job scheduling framework, Quartz. This project owes very much to original Java project, it’s father James House and the project contributors.

http://www.quartz-scheduler.net/

How to get started?

The official guide here: http://www.quartz-scheduler.net/documentation/quartz-2.x/quick-start.html

And the steps here:

  1. Create Console Application
  2. Install Quartz.NET from NuGet package by running following command

    Install-Package Quartz

    Quartz NuGet will install following packages at this time I writing the blog post

    <packages>
      <package id="Common.Logging" version="2.1.2" targetFramework="net45" />
      <package id="Quartz" version="2.2.4" targetFramework="net45" />
    </packages>
    
  3. Add following code in the namespace
  4. Program class

    class Program
        {
            static void Main(string[] args)
            {
                try
                {
                    //Configure simple logging
                    Common.Logging.LogManager.Adapter = new Common.Logging.Simple.ConsoleOutLoggerFactoryAdapter { Level = Common.Logging.LogLevel.Info };
    
                    // Grab the Scheduler instance from the Factory 
                    IScheduler scheduler = StdSchedulerFactory.GetDefaultScheduler();
    
                    // and start it off
                    scheduler.Start();
    
                    // define the job and tie it to our HelloJob class
                    IJobDetail job = JobBuilder.Create<HelloJob>()
                        .WithIdentity("job1", "group1")
                        .Build();
    
                    // Trigger the job to run now, and then repeat every 10 seconds
                    ITrigger trigger = TriggerBuilder.Create()
                        .WithIdentity("trigger1", "group1")
                        .StartNow()
                        .WithSimpleSchedule(x => x
                            .WithIntervalInSeconds(10)
                            .RepeatForever())
                        .Build();
    
                    // Tell quartz to schedule the job using our trigger
                    scheduler.ScheduleJob(job, trigger);
    
    
                    // some sleep to show what's happening
                    Thread.Sleep(TimeSpan.FromSeconds(60));
    
                    // and last shut down the scheduler when you are ready to close your program
                    scheduler.Shutdown();
                }
                catch (SchedulerException se)
                {
                    Console.WriteLine(se);
                }
    
    
                Console.WriteLine("Press any key to close the application");
                Console.ReadKey();
    
            }
        }
    

    Job class

    public class HelloJob : IJob
        {
            public void Execute(IJobExecutionContext context)
            {
                Console.WriteLine("Greetings from HelloJob!");
            }
        }
    
  5. The output like this.

Hope this help!

Create a free website or blog at WordPress.com.