引言
我在 *ASP.NET * framework 4的webforms网站上使用 *Quartz .NET *。基本上,用户应该能够手动启动一个批处理脚本,异步处理存储在数据库中的数千条记录。用户可以随时停止或暂停,调整一些变量,如果需要,继续处理(剩余记录)。
代码已完成,并在本地运行(开发人员计算机、win7、vs2010、sql server express 2008 R2)。
还在本地服务器上进行了测试(win server 2008 R2,sql server express 2008 R2)。它在两种环境下都能正常工作,测试时所有代码都是预编译的。问题是,一旦部署到远程服务器上(win server 2008 R2),它实际上应该运行在(托管环境,非共享,非集群),它不完全工作(见下面的详细信息)。调度程序创建,但触发器,因此作业,不激发。
(**注:**我知道你们中的一些人会建议使用Quartz作为Windows服务,但尽管这样做有好处,我还是想知道为什么它不能作为嵌入式解决方案工作,因为它应该像本地一样工作得很好)
详细信息
Quartz 2.1.2
Common.Logging 2.1.2
Common.Logging.NLog 2.0.0
NLog 2.0.1.2
全局.asax
public static ISchedulerFactory SchedulerFactory;
public static IScheduler Scheduler;
void Application_Start(object sender, EventArgs e)
{
SchedulerFactory = new StdSchedulerFactory();
Scheduler = SchedulerFactory.GetScheduler();
// Define a durable job instance (durable jobs can exist without triggers)
IJobDetail job = JobBuilder.Create<MyJobClass>()
.WithIdentity("MyJob", "MyGroup")
.StoreDurably()
.Build();
Scheduler.AddJob(job, false);
Scheduler.Start();
}
void Application_End(object sender, EventArgs e)
{
Scheduler.Shutdown(true);
}
process.aspx.cs(单击“开始”按钮)
// get records from DB, iterate, process, etc
...
IJobDetail job = ASP.global_asax.Scheduler.GetJobDetail(new JobKey("MyJob", "MyGroup"));
job.JobDataMap.Put("something1", 1);
job.JobDataMap.Put("something2", somevar);
ITrigger trigger = TriggerBuilder.Create()
.WithIdentity("MyTrigger", "MyGroup")
.StartNow()
.WithSimpleSchedule(x => x.WithIntervalInSeconds(5).RepeatForever())
.Build();
var triggersSet = new Quartz.Collection.HashSet<ITrigger> { trigger };
ASP.global_asax.Scheduler.ScheduleJob(job, triggersSet, true);
日志输出
本地日志
Default Quartz.NET properties loaded from embedded resource file
Using default implementation for object serializer
Using default implementation for ThreadExecutor
Initialized Scheduler Signaller of type: Quartz.Core.SchedulerSignalerImpl
Quartz Scheduler v.2.1.2.400 created.
RAMJobStore initialized.
Scheduler meta-data: Quartz Scheduler (v2.1.2.400) 'DefaultQuartzScheduler' with instanceId 'NON_CLUSTERED' Scheduler class: 'Quartz.Core.QuartzScheduler' - running locally. NOT STARTED. Currently in standby mode. Number of jobs executed: 0 Using thread pool 'Quartz.Simpl.SimpleThreadPool' - with 10 threads. Using job-store 'Quartz.Simpl.RAMJobStore' - which does not support persistence. and is not clustered.
Quartz scheduler 'DefaultQuartzScheduler' initialized
Quartz scheduler version: 2.1.2.400
Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED started.
Batch acquisition of 0 triggers
Batch acquisition of 0 triggers
它继续记录 * 0个触发的批量采集 *,直到点击按钮:
Default Quartz.NET properties loaded from embedded resource file
Batch acquisition of 1 triggers
Producing instance of Job 'MyGroup.MyJob', class=MyJobClass
Batch acquisition of 0 triggers
Calling Execute on job MyGroup.MyJob
Trigger instruction : NoInstruction
Batch acquisition of 1 triggers
Producing instance of Job 'MyGroup.MyJob', class=MyJobClass
Batch acquisition of 0 triggers
Calling Execute on job MyGroup.MyJob
Trigger instruction : NoInstruction
Batch acquisition of 1 triggers
部署日志
Default Quartz.NET properties loaded from embedded resource file
Using default implementation for object serializer
Using default implementation for ThreadExecutor
Initialized Scheduler Signaller of type: Quartz.Core.SchedulerSignalerImpl
Quartz Scheduler v.2.1.2.400 created.
RAMJobStore initialized.
Scheduler meta-data: Quartz Scheduler (v2.1.2.400) 'DefaultQuartzScheduler' with instanceId 'NON_CLUSTERED' Scheduler class: 'Quartz.Core.QuartzScheduler' - running locally. NOT STARTED. Currently in standby mode. Number of jobs executed: 0 Using thread pool 'Quartz.Simpl.SimpleThreadPool' - with 10 threads. Using job-store 'Quartz.Simpl.RAMJobStore' - which does not support persistence. and is not clustered.
Quartz scheduler 'DefaultQuartzScheduler' initialized
Quartz scheduler version: 2.1.2.400
Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED started.
这里是这样的。正如你所看到的,与其他日志相比,它没有尝试获取触发器(行 * 0触发器的批量获取 * 根本没有出现)。如果你还是点击了进程按钮,日志会添加一行:
Default Quartz.NET properties loaded from embedded resource file
但不会发生其他任何事情。记录不会被处理(我知道,因为每次处理记录时,都会在数据库中标记)。没有错误发生,但触发器没有触发,作业也没有执行。此外,CPU使用率在按钮点击时高达50%或更多,除非你转到IIS,否则不会下降,停止并重新启动应用程序池。此CPU消耗不会在本地发生。
更新1
按照LeftyX的建议,更改了单例的调度程序使用,但在远程服务器上仍获得相同的行为。
更新2
我还尝试使用ADOJobStore(而不是我正在使用的 RAMJobStore),现在它仍然可以在本地完美地工作;但仍然无法在线执行触发器(因此无法在线执行作业)。唯一的区别是,在线CPU使用率不会达到50%。现在我可以看到作业和触发器已创建(我查询了表,发现这些记录存在),但从未执行过。
4条答案
按热度按时间dfty9e191#
Quartz没有任何问题,这都是因为IIS应用程序池回收。我通过停止回收Quartz使用的池来修复此错误:
1.转到IIS管理器-〉应用程序池-〉创建一个新池,我将其命名为Scheduler(任何名称都可以)
1.选择计划程序池-〉高级设置
3.将你的Quartz站点部署到这个应用池中。然后向池中发送一个"唤醒你的应用"的请求,它会一直运行直到你停止它。
就是这样。
aiazj4mn2#
我注意到的一件事是在您的www.example.com应用程序中使用了
Scheduler
。asp.net application.应该使用单例对象。
在您
process.aspx.cs
此行中创建一个新的调度程序,但您应该使用在
Application_Start
中创建的静态调度程序。如果你想访问singleton示例,请在
Global.asax.cs
中使用一个公共成员:你可以在
process.aspx.cs
中引用它:另一个解决方案是使用依赖注入,你可以使用StructureMap找到一些here的信息,使用Unity找到一些here的信息。
更新:
您可以下载一个名为AspNet_Quartzhere的示例应用程序(asp.net 4.0),并查看它是如何工作的。
af7jpaap3#
问题与
IIS
有关,而与调度器Quartz.NET
、Hangfire
等无关,另一方面,网络上发布了很多解决方法,但只有一部分起作用,在我看来,不需要应用大量的配置设置,只需在发布应用的服务器上安装Keep Alive Service For IIS 6.0/7.5并享受即可,之后,在应用程序池回收、IIS/应用程序重新启动等操作之后,您发布的应用程序仍将处于活动状态。btqmn9zl4#
我刚刚遇到了一个类似的问题,可能会咬别人-它把我带到这个如此的问题后,打开调试和获得的“批采集0触发器”的消息。
我的工作是每两个小时这样的:
我想多做几次,所以每两分钟就像这样:
我甚至尝试了https://cronexpressiondescriptor.azurewebsites.net/,这给了我一个很大的线索,我应该更仔细地阅读:每2小时,在一个月的第0天这最终让我意识到我真正的意思是:
因此,教训是,当“左移”你的cron,回填 *,而不是0。
希望这对其他人有帮助。