tags:

views:

90

answers:

2

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

+1  A: 

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;
 }
TskTsk
A: 

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

Mauricio Scheffer