How to add/remove jobs at runtime using Quartz.NET/TopShelf?

683 views
Skip to first unread message

Jeff Bowman

unread,
Oct 13, 2014, 11:52:00 PM10/13/14
to quar...@googlegroups.com
New to Quartz.NET; my service code is below.

I'd like to be able to add and schedule new jobs without having to recompile/restart the service every time. In other words, without hard-coding the job reference as below.

I've found a few candidate examples by searching--and one with Example #15 from the source--but all assume usage without TopShelf. As we can see below, TopShelf wants a hard-coded delegate reference for its ScheduleQuartzJob() call (which delegate is itself built with a series of hard-coded delegates).

How to do this with AdoJobStore/XML persistence under TopShelf?

Thanks,
Jeff Bowman
Fairbanks, Alaska




 
Sub Main()
   
Dim oSchedule As Action(Of SimpleScheduleBuilder)
   
Dim oTrigger As Func(Of ITrigger)
   
Dim oDetail As Func(Of IJobDetail)
   
Dim oJob As Action(Of QuartzConfigurator)

    oSchedule
= Function(ScheduleBuilder) As SimpleScheduleBuilder
                 
Return ScheduleBuilder.WithIntervalInSeconds(5).RepeatForever
               
End Function

    oTrigger
= Function() As ITrigger
                 
Return TriggerBuilder.Create.WithIdentity(QbBackup.Job.Trigger, QbBackup.Job.Group).WithSimpleSchedule(oSchedule).Build
               
End Function

    oDetail
= Function()
               
Return JobBuilder.Create(Of QbBackup.Job).WithIdentity(QbBackup.Job.Name, QbBackup.Job.Group).Build
             
End Function

    oJob
= Function(Configurator As QuartzConfigurator)
             
Return Configurator.WithJob(oDetail).AddTrigger(oTrigger)
           
End Function

   
HostFactory.Run(Sub(Configurator)
                     
Configurator.Service(Of Manager)(Sub(Service)
                                                         
Service.ConstructUsing(Function(Factory) As ServiceControl
                                                                                 
Return New Manager
                                                                               
End Function)

                                                         
Service.WhenStarted(Function(Notifier, HostControl) As Boolean
                                                                               
Return Notifier.StartService(HostControl)
                                                                             
End Function)

                                                         
Service.WhenStopped(Function(Notifier, HostControl) As Boolean
                                                                               
Return Notifier.StopService(HostControl)
                                                                             
End Function)

                                                         
Service.ScheduleQuartzJob(oJob)
                                                       
End Sub)

                     
Configurator.SetDescription(SchedulerInfo.Description)
                     
Configurator.SetServiceName(SchedulerInfo.Product)
                     
Configurator.SetDisplayName(SchedulerInfo.Title)
                     
Configurator.StartAutomatically()
                     
Configurator.RunAsLocalSystem()
                   
End Sub)
 
End Sub




 
Imports Common.Logging

 
Public Class Job
   
Implements IJob

   
Private Shared Logger As ILog = LogManager.GetLogger(GetType(Job))

   
Public Sub Execute(Context As IJobExecutionContext) Implements IJob.Execute
     
Try
       
Job.Logger.Info(Now.ToString)

     
Catch ex As Exception
       
Throw New JobExecutionException(ex.Message, ex)

     
End Try
   
End Sub



   
Public Shared ReadOnly Property Name As String
     
Get
       
Return QbBackupInfo.Product
     
End Get
   
End Property



   
Public Shared ReadOnly Property Trigger As String
     
Get
       
Return "{0}Trigger".ToFormat(Job.Name)
     
End Get
   
End Property



   
Public Shared ReadOnly Property Group As String
     
Get
       
Return "{0}Group".ToFormat(Job.Name)
     
End Get
   
End Property
 
End Class



Jay Vilalta

unread,
Oct 14, 2014, 1:04:37 PM10/14/14
to quar...@googlegroups.com
You could split up the service code from the "application" code and put them in separate dlls.

In our setup we install quartz as a service, then connect to it via remoting to schedule jobs. Your job dlls have to be copied to where the scheduler is. This allows you to add new jobs without recompiling the scheduler itself but it doesn't solve the restarting the service part. It has been one of my wants for Quartz.Net to not require a restart if you update the job dlls but it's a fair amount of work to have quartz.net start separate app domains like asp.net does so that you can update job dlls on the fly. It would be cool though :-)

Hope this helps.

--
You received this message because you are subscribed to the Google Groups "Quartz.NET" group.
To unsubscribe from this group and stop receiving emails from it, send an email to quartznet+...@googlegroups.com.
To post to this group, send email to quar...@googlegroups.com.
Visit this group at http://groups.google.com/group/quartznet.
For more options, visit https://groups.google.com/d/optout.

Jeff Bowman

unread,
Oct 14, 2014, 5:22:38 PM10/14/14
to quar...@googlegroups.com
Hi Jay, thanks for your reply. FYI that was me on the StackOverflow question as well.

This is pretty much what I've got in mind (excepting WCF instead of Remoting); I suppose I can live with restarting, but rebuilding is a deal-killer.

But the problem is not so much in the architecture as in the syntax. All of the runtime-scheduled samples I've seen go something like this:

Dim oProperties As NameValueCollection
Dim oScheduler As IScheduler
Dim oFactory As ISchedulerFactory

oProperties
= New NameValueCollection

'Build up properties here
'
...
'...
'
...

oFactory
= New StdSchedulerFactory(oProperties)
oScheduler
= oFactory.GetScheduler()
oScheduler
.Start()

But this doesn't work in a TopShelf service. See the hardcoded delegate reference in the ScheduleQuartzJob() call from my original post? That job is compiled into the code, no matter where the assembly sits. There doesn't seem to be a way to send oScheduler (a standard class/variable reference) to TopShelf (requires a delegate).

This is a companion problem to the 'Duplicate Jobs' problem -- I believe that the answer to one is going to be the answer to the other.

What do you think? Is there any hope for dynamic scheduling under TopShelf?


Thanks,
Jeff Bowman
Fairbanks, Alaska


Jay Vilalta

unread,
Oct 15, 2014, 2:51:30 PM10/15/14
to quar...@googlegroups.com
These are the files you can use to run Quartz.Net as windows service wrapped in topshelf.Specifically look at Program.cs, which is the topshelf wrapper.

FWIW Quartz.Net doesn't support WCF out of the box so unless you're going to implement that wrapper, then you'll have to use remoting.

J
Reply all
Reply to author
Forward
0 new messages