Share via


每分钟一次循环运行批处理作业

这里的问题是在AX2009中创建一个服务器端批处理作业,以每分钟一次的频率循环运行。这个作业本身只执行几秒钟,但是批处理作业在几分钟之内是完成不了的。所以下一个批处理作业不是在一分钟后开始运行,而是我们不希望看到的几分钟以后运行。

首先,我想阐明这个场景中后台发生了什么。之后,在此基础上我将给出解决方案:

后台究竟发生了什么:

让我们假设有一个简单的批处理作业,它的具体内容是次要的,只是一个能在一分钟内完成的简单批处理作业。它从12:00:00开始以每分钟一次的频率被送到批次,并将一直持续。

在AOS的后台有一个线程,这个线程每60秒检索是否有新的批处理作业来处理。它是通过调用batchRun.serverGetTask()函数来做到这点的。值得注意的是,在AX配置中的每个批处理线程会触发同一个过程:每当这些线程完成了作业并可以执行新的作业时,它们会调用batchRun.serverGetNextTask()函数,这个函数像之前一样调用函数batchRun.serverGetTask()。我之所以提及这个过程是因为:如果当前没有批处理线程在运行,请求新的作业是每60秒发生一次的。但是在一个有许多批处理任务执行的服务器上,每一个批处理线程一旦空闲就会请求新的作业,那么请求时间将可能多于或少于60秒了。但是线程将一直持续工作,直到没有作业需要执行。当没有作业需要执行时,那么线程请求新的作业的频率仅仅是每60秒一次。

这是可能造成延迟的第一部分原因: 在上述简单的例子中,如果当前AOS上没有其它批处理作业在运行,那么当一个新的作业被送到队列中,它有可能要等待60秒才能被处理。因此假设新的作业在12:00:00被送到队列,那么因为那个60秒的间隔,最坏情况下它将在12:00:59才被处理。

造成延迟的第二部分原因是作业本身的执行所需要的时间。在上述列子中,如果这个作业需要执行20秒,那么它将执行到12:01:18。

最后,在AOS上还有一个后台的线程,它每隔60秒调用函数batchRun.serverProcessFinishedJobs();这个函数是不会被批处理线程调用的,它只被AOS管理会话调用。你可以看到函数batchRun.serverProcessFinishedJobs()还会检索BatchGlobal表,因此即使在多AOS环境中,我们仍然不会在每60秒内调用这个函数超过一次。之前的例子中,作业在12:01:18执行结束。但是因为60秒的间隔,所以在最坏情况下,它将在12:02:17才被执行。设置批处理作业为完成状态是由batchRun.serverProcessFinishedJobs()函数来完成的。

这个函数也设置下一次请求的时间,这个时间是通过初始时间(在之前的例子中:12:00:00)与当前时间(12:02:17)比对得到的。这个函数会加上间隔时间来保证新的开始时间晚于当前时间而不是过去,所以函数得到的下一次请求时间将是12:03:00,然而我们希望的却是基于每分钟循环的12:01:00,错误就这样发生了。

我们如何解决这个问题:

前面我们已经看到:在最坏情况下,新的作业需要等待59秒才能被开始执行,这个作业本身还要执行一段时间(比如:20秒),设置作业状态为结束最多需要59秒。所以,最坏情况我们总共需要”1:58+作业执行时间”。为了突破这个瓶颈,我们可以尝试一些更创新的设置:我们可以创建5个错位但执行相同流程的作业,而不只是一个:

作业1设置为12:01:00开始执行,每5分钟执行一次

作业2设置为12:02:00开始执行,每5分钟执行一次

作业3设置为12:03:00开始执行,每5分钟执行一次

作业4设置为12:04:00开始执行,每5分钟执行一次

作业5设置为12:05:00开始执行,每5分钟执行一次

这些作业带来的效果是:作业的实例有规律的每分钟执行一次,而5分钟的间隔意味着潜在的”1:58+作业执行时间”的瓶颈将不再影响作业的重复执行,因为我们有5分钟的空间来容纳这段额外的时间。这样的方法保证了每分钟执行一次的频率。

在此基础上,我对Classes\BatchRun(参考附属的XPO,你需要将扩展名修改为*.xpo)做了一些小修改来增加检查完成的作业的频率。在函数serverGetTask()中,我添加了一个额外的对函数serverProcessFinishedJobs()的调用,在这个函数中,我修改了对batchGlobal表的检查部分,使得检查时间间隔从60秒缩短为30秒。这可能带来一些额外的性能开销,因此如果您需要尝试如此修改,那么您的测试工作是很重要的。我们在标准情况下每60秒检查一次的原因正是出于对性能的考虑。当然您可以通过测试很好地将时间间隔调整为1-60秒之间。

举例说明修改前后的时间:参数origStartDateTime表示计划的开始时间,参数startDateTime是实际的开始时间,参数endDateTime是记录的结束时间。这些参数可以从Tables\BatchJobHistory获得。

修改前 :

StartDateTime

EndDateTime

OrigStartDateTime

30/03/2011 09:14:09

30/03/2011 09:16:09

30/03/2011 09:12:34

30/03/2011 09:17:21

30/03/2011 09:18:09

30/03/2011 09:16:34

30/03/2011 09:19:33

30/03/2011 09:20:09

30/03/2011 09:18:34

30/03/2011 09:20:42

30/03/2011 09:22:09

30/03/2011 09:20:34

30/03/2011 09:22:52

30/03/2011 09:24:09

30/03/2011 09:22:34

30/03/2011 09:25:00

30/03/2011 09:26:09

30/03/2011 09:24:34

30/03/2011 09:27:09

30/03/2011 09:29:09

30/03/2011 09:26:34

30/03/2011 09:30:18

30/03/2011 09:31:09

30/03/2011 09:29:34

修改后 :

StartDateTime

EndDateTime

OrigStartDateTime

31/03/2011 10:58:35

31/03/2011 10:59:35

31/03/2011 10:58:00

31/03/2011 10:59:45

31/03/2011 11:00:35

31/03/2011 10:59:00

31/03/2011 11:00:53

31/03/2011 11:01:35

31/03/2011 11:00:00

31/03/2011 11:01:01

31/03/2011 11:01:35

31/03/2011 11:01:00

31/03/2011 11:02:09

31/03/2011 11:02:35

31/03/2011 11:02:00

31/03/2011 11:03:17

31/03/2011 11:04:25

31/03/2011 11:03:00

31/03/2011 11:04:25

31/03/2011 11:05:32

31/03/2011 11:04:00

31/03/2011 11:05:32

31/03/2011 11:06:39

31/03/2011 11:05:00

你可以看到在“修改后”的例子中,有两个线程的结束时间是一致的,这是因为测试中在线程特定的时间里,它们是从serverProcessFinishedTasks()函数的同一实例得来的,但即使有这个异常的数据,作业开始执行时间间隔仍然是大约1分钟。

原文地址:

https://blogs.msdn.com/b/emeadaxsupport/archive/2011/04/14/running-ax2009-batches-with-a-recurrence-of-1-minute.aspx

Class_BatchRun_increasedFreq.xpo.txt