mausch / QuartzNetWebConsole

Embeddable Quartz.Net web console
Other
162 stars 63 forks source link

Issue in connecting to a remote Quartz.Net scheduler (windows service) #22

Open ghost opened 10 years ago

ghost commented 10 years ago

For testing I'm running the Quartz.net scheduler as windows service under the same box, where my web-app (having embedded quartznet web console) is also hosted.

Problem description:

The windows service is started manually and runs fine with logging and adojobstore.

The web app has the following code to initialize the quartz.net web console to the quartz.net scheduler, and also runs fine without any exception:

NameValueCollection properties = new NameValueCollection(); properties["quartz.scheduler.instanceName"] = "SPDQuartzScheduler";

// set thread pool info properties["quartz.threadPool.type"] = "Quartz.Simpl.SimpleThreadPool, Quartz"; properties["quartz.threadPool.threadCount"] = "10"; properties["quartz.threadPool.threadPriority"] = "Normal";

// set remoting expoter properties["quartz.scheduler.proxy"] = "true"; properties["quartz.scheduler.proxy.address"] = "tcp://localhost:555/SPDQuartzScheduler";

// First we must get a reference to a scheduler ISchedulerFactory sf = new StdSchedulerFactory(properties); quartzScheduler = sf.GetScheduler();

//Assign webconsole to scheduler QuartzNetWebConsole.Setup.Scheduler = () => quartzScheduler;

When we visit the ..\quartz\index.html page in the web app, the following exception is thrown:

Quartz.SchedulerException: Operation not supported for remote schedulers. at Quartz.Impl.RemoteScheduler.get_ListenerManager() at QuartzNetWebConsole.Utils.SchedulerWrapper.get_ListenerManager() at QuartzNetWebConsole.Controllers.IndexController.Execute(HttpContextBase context, Func`1 getScheduler) at QuartzNetWebConsole.ControllerFactory.<.ctor>b__6(HttpContextBase ctx) at MiniMVC.HttpHandler.ProcessRequest(HttpContext context) at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)

mausch commented 10 years ago

This should fix it:

  1. Implement a mock of Quartz.IListenerManager (let's call it MockListenerManager)
  2. In https://github.com/mausch/QuartzNetWebConsole/blob/master/QuartzNetWebConsole/Utils/SchedulerWrapper.cs#L132 catch the SchedulerException you got and return MockListenerManager instead.

MockListenerManager should:

  1. return empty lists for all methods of IListenerManager that return lists,
  2. return true for all methods that return bool
  3. do nothing for all methods that return void.
ghost commented 10 years ago

Hello,

Thanks for such a prompt response. By any means, is it possible for you to implement this change (the web-console code changes), and provide a download for DLL. I know it may be too much to ask, however others may be benefited from this too...if you think these changes are imperative to support a remote scheduler.

If you would like to do it as a one-off change for us, do let us know. Thanks,

ghost commented 10 years ago

I did try your suggestion pulling the latest version of 0.3 code from GitHub, however ran into a number of issues resolving lib dependencies. After some digging the quartznetwebconsole lib I built is built successfully, but it does not work after I use it in my web-app. lots of dll load issues are generated, as soon as I go to ~/quartz/index.html url.

I don't have much experience in dealing with some of these issues. Will you be able to help with the a build that has the changes (you suggested), in?

mausch commented 10 years ago

I will not implement this myself. Open source does not work like that. But I will try to assist you as much as I can. What build issues do you have?

alexminza commented 9 years ago

What is the correct way to connect to a remote scheduler?

We run Quartz.net in a clustered environment with Quartz.Impl.AdoJobStore.JobStoreTX job store and export it with Quartz.Simpl.RemotingSchedulerExporter.

Here is the code setup in the QuartzNetWebConsole app:

        protected void Application_Start(object sender, EventArgs e)
        {
            #region QuartzNetWebConsole remote scheduler setup

            var quartzProperties = new NameValueCollection();
            quartzProperties["quartz.scheduler.instanceName"] = ConfigurationManager.AppSettings["QuartzSchedulerName"];
            quartzProperties["quartz.scheduler.instanceId"] = Environment.GetEnvironmentVariable("RoleInstanceID") ?? Environment.MachineName; //"AUTO"

            //avoid running any jobs locally
            quartzProperties["quartz.threadPool.type"] = "Quartz.Simpl.ZeroSizeThreadPool, Quartz";
            quartzProperties["quartz.threadPool.threadCount"] = "0";

            quartzProperties["quartz.scheduler.proxy"] = "true";
            quartzProperties["quartz.scheduler.proxy.address"] = ConfigurationManager.AppSettings["QuartzProxyAddress"];

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

            QuartzNetWebConsole.Setup.Scheduler = () => scheduler;

            #endregion
        }

QuartzSchedulerName setting is the same as the clustered schedulers. QuartzProxyAddress is the same as we use for the CrystalQuartz console.

[RemotingException: Server encountered an internal error. For more information, turn off customErrors in the server's .config file.]
   System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg) +348
   System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type) +1748
   Quartz.Simpl.IRemotableQuartzScheduler.IsTriggerGroupPaused(String groupName) +0
   Quartz.Impl.RemoteScheduler.CallInGuard(Func`2 func) in c:\Program Files (x86)\Jenkins\workspace\Quartz.NET\src\Quartz\Impl\RemoteScheduler.cs:587

[SchedulerException: Error communicating with remote scheduler.]
   Quartz.Impl.RemoteScheduler.CallInGuard(Func`2 func) in c:\Program Files (x86)\Jenkins\workspace\Quartz.NET\src\Quartz\Impl\RemoteScheduler.cs:593
   QuartzNetWebConsole.Utils.SchedulerWrapper.IsTriggerGroupPaused(String groupName) in g:\prg\QuartzNetWebConsole\QuartzNetWebConsole\Utils\SchedulerWrapper.cs:102
   QuartzNetWebConsole.Controllers.<>c__DisplayClass7.<Execute>b__0(String t) in g:\prg\QuartzNetWebConsole\QuartzNetWebConsole\Controllers\IndexController.cs:14
   System.Linq.WhereSelectListIterator`2.MoveNext() +261
   System.Linq.Buffer`1..ctor(IEnumerable`1 source) +488
   System.Linq.Enumerable.ToArray(IEnumerable`1 source) +103
   QuartzNetWebConsole.Controllers.IndexController.Execute(HttpContextBase context, Func`1 getScheduler) in g:\prg\QuartzNetWebConsole\QuartzNetWebConsole\Controllers\IndexController.cs:13
   System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +1386
   System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +2408
   System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +169

What are we doing wrong? Is this scenario supported?

mausch commented 9 years ago

I've never needed to connect to a remote Quartz instance. The comments here outline a solution/implementation for some of it. In your particular case, it seems as if IsTriggerGroupPaused is not supported in a remoting scenario. It is not clear to me what is and isn't supported in a remoting scenario. In addition to that, not all job stores support every action in the interface, which leads to issues like https://github.com/mausch/QuartzNetWebConsole/issues/18 . Again, it's not clear what's supported and what's not. So for a proper solution someone would have to write exhaustive tests for all methods in the interface with remoting / different job stores.

andreidobre commented 8 years ago

Hello and good day! Is it possible to connect remotely to another quartz server using the IP address? To be more precise: I have listed a few jobs in the quartz_jobs.xml and they are triggered at the specified hours by the scheduler. In this case, I use the windows service to execute the jobs. I want to make another external application (independent from the quartz DLL) from where I can execute immediately one of the jobs from my quartz_jobs.xml file. I want to access the service and pass him two parameters, the name of the job and let's say the IP address of the server. I don't want to use the quartz.scheduler.proxy.address because this will intrefier with my config files. I want this external application to be as independent as possible. Is it possible, or the proxy.address is the only way?

Thank you for your time, Dobre Andrei

mausch commented 8 years ago

@andreidobre please use the Quartz.NET mailing list for any questions about Quartz.NET. This issue is specifically about QuartzNetWebConsole connecting to a remote instance. Proxy or not should not affect QuartzNetWebConsole.

andreidobre commented 8 years ago

thank you