Search code examples
c#.netasp.net-mvcquartz.net.net-remoting

MVC3 webapp task scheduling with Quartz.NET


I need your advice for scheduling tasks in the MVC3 Webapp.

My task is to create some generic scheduler for different services in the webapp that can be used later in development. For example we have some available tasks that user can schedule whenever he wants.

I didn't want to reinvent the wheel and found the Quartz.Net library that can be used to create the scheduler.

I know that it's not a good idea to host scheduling inside webapp cause webserver can recycle the application pools, etc, so i decided to use it inside a Windows Service and then using Quartz.NET remoting feature to trigger tasks inside my webapp.

But i've found some issues with that. Correct me if I'm wrong, but when i tried to use the Quartz.NET remoting it runs the job inside the Windows Service process, it means that it needs to know about all types inside my webapp, so all the assemblies of the webapp should be referenced by it, and i need to have another config file for database, etc. So in case I write new job class, i can't easily schedule it, i need to stop the service and renew the library for it, so it's not very generic approach.

I can't find any info that Quartz.NET can run jobs only based on it's interface.

So I came up with idea to write my own scheduler that will be hosted in the Windows Service, and will have some IJob interface that will be implemented in the webapp. I will also use .Net remoting using IPC channel. So the webapp will be like .Net Remoting Server, and when i want to add some new job and then schedule it, i will just have to write new job that implements IJob interface. I will register it as

        IpcChannel channel = new IpcChannel("CurrentIPC");

        ChannelServices.RegisterChannel(channel);

        RemotingConfiguration.RegisterWellKnownServiceType(
            typeof(SimpleJob), "SimpleJob", WellKnownObjectMode.SingleCall);
        RemotingConfiguration.RegisterWellKnownServiceType(
            typeof(ComplexObject), "ComplexObject", WellKnownObjectMode.SingleCall);

in this case i will have two Job types registered. Then when scheduling the job i will pass the name of the class and on the Windows Service side that will stand for client (executing objects on the webapp side) i will just bind the passed name of the class with IJob like this:

Dictionary<string, IJob> jobs = new Dictionary<string, IJob>();
    void AddJob(string name)
    {
        IJob obj = (IJob)Activator.GetObject(typeof(IJob), string.Format("ipc://CurrentIPC/{0}", name));
        jobs.Add(name, obj);
    }

So now i don't need to bother about references to my app and other stuff, the scheduler will do it's job without knowing anything, just IJob interface and executing tasks on the webapp side.

If i'm wrong or it's too complex and there are some other simpler methods of doing this, or there are some pitfalls that i'm not aware of, can you help me with that? Thank you.

P.S. Also there was an idea to have separate scheduler that will run the web app methods directly by executing a link to specified service in the web app, for example "http://localhost:3030/Request/12" and that's all, but in my web app you should be authorized to execute such request and again we have issues we need to resolve, and we will have additional load to the webserver with such requests in case of thousands of scheduled tasks.


Solution

  • I think you are on the right track, I would create the scheduler using Quartz.NET and host it in a Windows Service because of the app pool recycling issue.

    It will trigger tasks/services in your webapp using specific URL:s for each task/service either in your web app or a separate web service instance.

    Using this separation the scheduler only needs to know about the urls and the schedule and does not need to reference your app directly. This is also reusable in future projects.