Search
Close this search box.

Quartz.Net Windows Service on Server Important Configuration Steps To Remember

Are you running Quartz.Net as a windows service on a remote server and trying to connect to it from a client to schedule jobs? Then I would highly recommend reading the below listed configuration steps to save your self from endless hours of debugging.

  • 01 – How to ensure that the Quartz.NET service is executing jobs on the server and not locally?
  • 02 – Fixing “Scheduler with the name xxx already exists.” issue

If you are new to Quartz.Net I would recommend going through,

01 – How to ensure that the Quartz.NET service is executing jobs on the server and not locally?

To ensure that Quartz.Net schedules the job on the *remote server* and not on the local instance you need to set the thread count to 0 along with other properties shown below at the time of instantiating a new instance of the scheduler service,

using System;

using System.DirectoryServices;

using System.Collections;

using System.Text;

using System.Forms;
// address = string.Format("tcp://{0}:{1}/{2}", server, port, scheduler)
private static NameValueCollection GetProperties(string address) {
  var properties = new NameValueCollection();
  properties["quartz.scheduler.instanceName"] = "ServerScheduler";
  properties["quartz.scheduler.proxy"] = "true";
  properties["quartz.threadPool.threadCount"] = "0";
  properties["quartz.scheduler.proxy.address"] = address;
  return properties;
}

}  // End class

SNAGHTML3a6dd4be

Figure 1 – Quartz.Net config, contains useful details, does not need to be changed

Value of the properties that need to be passed while instantiating a new instance of Quartz service,

Address: The address needs to be passed in the format tcp://NameOfSeverWhereQuartzIsInstalled:555/QuartzScheduler

Instance Name: You can find the instance name from the Quartz.Net config file on the server. See in the config above, the instance name is ‘ServerScheduler’

Proxy: Set the proxy to true

ThreadCount: If you don’t specify the threadcount to 0, quartz.net will spin a local instance of the service to schedule your job. This means, your job would be scheduled but not on the server that you intended for it to be scheduled. The down side is, as soon as the local process terminates, the schedule will be lost.

The values you specify for the properties before instantiating the Quartz scheduler will have precedence over the values in the config file.

How to validate that the Quartz.Net scheduler service is scheduling remotely and not locally?

You can use the GetMetaData() method on the instance of Scheduler to get information such as the version of quartz.net, threadpool size, jobStoreType, jobStorePersistanceType, etc. This important method also returns the property ‘IsRemote’. If you have correctly configured the scheduler and correctly instanciated it, the value of this property should be ‘True’

image

02 – Fixing “Scheduler with the name xxx already exists.” issue

This would typically happen if you try to instantiate a new instance of the scheduler when you already have one active instance loaded in the process. The easiest way to avoid this is by implementing Scheduler instantiation using the singleton pattern. See the sample code for instantiating Quartz.Net using the Singleton pattern.

Scheduler is a singleton implementation. The class is instantiated only when the server name, port number and scheduler name input parameters are passed. Using this allows you to invoke the StdSchedulerFactory method and search if there is already an instance of scheduler instantiated using these properties. If so, return that instance other wise create a new instance and remember it.

public class Scheduler {
  public readonly IScheduler Instance;
  public string Address { get; private set; }
  public string JobName { get; set; }
  public string JobGroup { get; set; }
  public int Priority { get; set; }
  public string CronExpression { get; set; }

  private readonly ISchedulerFactory _schedulerFactory;

  public Scheduler(string server, int port, string scheduler) {
    Address = string.Format("tcp://{0}:{1}/{2}", server, port, scheduler);
    _schedulerFactory = new StdSchedulerFactory(GetProperties(Address));

    try {
      Instance = _schedulerFactory.GetScheduler();

      if (!Instance.IsStarted)
        Instance.Start();
    } catch (SchedulerException ex) {
      throw new Exception(string.Format("Failed: {0}", ex.Message));
    }
  }

  private static NameValueCollection GetProperties(string address) {
    var properties = new NameValueCollection();
    properties["quartz.scheduler.instanceName"] = "ServerScheduler";
    properties["quartz.scheduler.proxy"] = "true";
    properties["quartz.threadPool.threadCount"] = "0";
    properties["quartz.scheduler.proxy.address"] = address;
    return properties;
  }

  public IScheduler GetScheduler() {
    return Instance;
  }
}

If you wanted to call Scheduler then you should be using something like the code sample below…

Simply calling the Scheduler class with the name of the server where Quartz is installed, the port on which the quartz service is listening and the name of the scheduler.

public SchedulerMetaData GetMetaData()
{
        var scheduler = new Scheduler("ServerName", Convert.ToInt32("PortNumber"), "Scheduler"));
        return scheduler.GetMetaData();
}

I hope this helps!

This was fifth in the series of posts on enterprise scheduling using Quartz.net, in the next post I’ll be covering how to expose the functionality of the Quartz.Net scheduling service via WebService. All Quartz.Net specific blog posts are listed here. Thank you for taking the time out and reading this blog post. If you enjoyed the post, remember to subscribe to http://feeds.feedburner.com/TarunArora. Stay tuned!

This article is part of the GWB Archives. Original Author: Tarun Arora

Related Posts