Pregunta

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.

¿Fue útil?

Solución

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.

Otros consejos

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...

Why complicate? why not make it simple and use an external service to run webhooks at a period of time?

I use this service and I've been happy, though it's so easy that I could create my own service based on this simple procedure:

http://momentapp.com/

to simplify the call:

private void Run() {
     try {
        var work = RequestNewMessage();  // get work
        ProcessWork(work);  // process work
        // Log work 
     }
     catch(Exception ex) {
        // Log Error
     }
     finally {
        // set job for now plus1 minute
        SetRecuringJob(DateTime.UtcNow.AddMinute(1)); 
     }
}

private void SetRecuringJob(DateTime dt) {
    PostJob("https://momentapp.com/jobs/new?job[at]={0:s}&job[method]=POST&job[uri]=http://yourapp.com/", dt);
}

A bit late I imagine, but could still be useful for others.

Here's a project I've spent quite a bit of time with that seems to fulfil most the requirements stated - in fact, I use it almost exclusively for callback jobs as described in the question. It's also what we use internally, so I do try to keep it updated.

http://backgroundworker.codeplex.com/

It's pretty similar to Quartz, but more focussed towards managing jobs and their data.

If your issue is you don't want to reference the entire web app from the WindowService, and I agree with that, why don't you simply create a utility dll implementing a generic job able to call your web app via a plain http url and implements the "actions" as a WCF REST service? This I think will cleanup a bit the architecture and keep insulated ( and reusable ) the scheduler service in your organization.

I might be missing a requirement, but as you seem to be able to install a custom service, it sounds like you have full control over that machine. So you might as well schedule a Windows Task for your recurring job, which should give you a pretty solid basis for recurring tasks.

You can then schedule a VB script to load a url on a timely basis, like here: http://4rapiddev.com/internet/call-or-open-a-web-page-url-by-using-windows-task-scheduler-or-cronjob/

Anything goes of course, from batch file, over powershell to custom executable.

Upsides to this approach:

  • You can rely on default OS behaviour for what the OS is good at: scheduling :)
  • There's already a UI for the admin (albeit not a web UI)
  • You have no dependency but the OS

Possible downsides:

Edit: I did seem to have missed the requirement on the authentication, but when you're using Windows, you could allow for Windows authentication within a certain area of your app. And because you're using Scheduled Tasks which are Windows Authenticated, you have this covered. I never heavily used Windows authentication within an ASP.NET app, but you might even get away with only custom configuration and no extra programming.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top