3
votes

We have a Quartz.Net installation running as a Windows Service. That's running fine. We also have a ASP.Net app that adds/edits jobs and monitors jobs. We occasionally get an error in the ASP.Net application. The errors are either "The Scheduler has been Shutdown." or "Scheduler with name 'JOB_SCHEDULER_NAME' already exists."

If you refresh the page, it works fine. I have been able to recreate the problem by quickly opening multiple instances of the same page over and over. So, my current theory is that the way we're getting an instance of the Scheduler is not thread-safe.

As an example, here is a simplified version of how we're getting job information:

var schedulerFactory = new StdSchedulerFactory();
var scheduler = schedulerFactory.GetScheduler();
var jobDetail = scheduler.GetJobDetail("SomeJobName", "SomeJobGroup");

This is being done when loading a page in the ASP.Net application.

The ASP.Net's config setup is:

<quartz>
  <add key="quartz.scheduler.instanceName" value="COMPANY_NAME_JobScheduler" />
  <add key="quartz.scheduler.instanceId" value="Provider.DEV" />
  <add key="quartz.jobStore.type" value="Quartz.Impl.AdoJobStore.JobStoreTX, Quartz" />
  <add key="quartz.jobStore.useProperties" value="true" />
  <add key="quartz.jobStore.dataSource" value="default" />
  <add key="quartz.jobStore.tablePrefix" value="QRTZ_" />
  <add key="quartz.jobStore.lockHandler.type" value="Quartz.Impl.AdoJobStore.UpdateLockRowSemaphore, Quartz" />
  <add key="quartz.jobStore.driverDelegateType" value="Quartz.Impl.AdoJobStore.SqlServerDelegate, Quartz " />
  <add key="quartz.dataSource.default.connectionString" value="server=PROD_SQL_SERVER;uid=SQL_USER;pwd=SQL_PASSWORD;database=Scheduler" />
  <add key="quartz.dataSource.default.provider" value="SqlServer-20" />
</quartz>

The Windows Service is initializing the scheduler like this:

var schedulerFactory = new StdSchedulerFactory();
var scheduler = schedulerFactory.GetScheduler();

The Windows Service config is:

<quartz>
  <add key="quartz.scheduler.instanceName" value="COMPANY_NAME_JobScheduler" />
  <add key="quartz.scheduler.instanceId" value="Service.PROD" />

  <add key="quartz.threadPool.type" value="Quartz.Simpl.SimpleThreadPool, Quartz" />
  <add key="quartz.threadPool.threadCount" value="10" />
  <add key="quartz.threadPool.threadPriority" value="2" />

  <add key="quartz.jobStore.misfireThreshold" value="60000" />
  <add key="quartz.jobStore.type" value="Quartz.Impl.AdoJobStore.JobStoreTX, Quartz" />
  <add key="quartz.jobStore.useProperties" value="true" />
  <add key="quartz.jobStore.dataSource" value="default" />
  <add key="quartz.jobStore.tablePrefix" value="QRTZ_" />
  <add key="quartz.jobStore.lockHandler.type" value="Quartz.Impl.AdoJobStore.UpdateLockRowSemaphore, Quartz" />
  <add key="quartz.jobStore.driverDelegateType" value="Quartz.Impl.AdoJobStore.SqlServerDelegate, Quartz " />

  <add key="quartz.dataSource.default.connectionString" value="server=PROD_SQL_SERVER;uid=SQL_USER;pwd=SQL_PASSWORD;database=Scheduler" />
  <add key="quartz.dataSource.default.provider" value="SqlServer-20" />
</quartz>

Is there better way to "query" the scheduler?

Edit: added more config info

3
More information needed. For example: what's the scheduler factory configuration? (both at the client and at the server). Where are you instantiating the scheduler factory and the scheduler in the client? - Mauricio Scheffer
Added more info. Does that help? - david.mchonechase

3 Answers

5
votes

We've set up the scheduler to be a singleton in our application, which fixed the problem for us:

public class MyScheduler
{
    static MyScheduler()
    {
        _schedulerFactory = new StdSchedulerFactory(getProperties());
        _scheduler = _schedulerFactory.GetScheduler();
    }
    public static IScheduler GetScheduler()
    {
        return _scheduler;
    }

    private static readonly ISchedulerFactory _schedulerFactory;
    private static readonly IScheduler _scheduler;
 }
0
votes

Instead of having both schedulers connect directly to the database, try making the web scheduler connect to the service scheduler through remoting.

0
votes

As Maurice indicates, a better approach may be to use remoting. You can look at this related question: Use one windows service to execute jobs and two web applications to schedule jobs