Spring 批处理作业调度程序在运行几次后停止执行
Spring Batch Job scheduler stops being executing after several runs
在一个项目中,我们必须 运行 一个定期启动的作业(现在在 QA env 上每 5 分钟一次)为 40k 用户处理一些分配。
我们决定使用 Spring Batch,因为它非常适合并使用几乎默认配置实现它(例如,它在引擎盖下使用 SyncTaskExecutor
)。
好的,所以,有一个作业由一个步骤组成:
- 开箱即用
HibernatePagingItemReader
- 在内存中执行轻量级计算的自定义
ItemProcessor
- 自定义
ItemWriter
通过多个 JPQL 和本机查询将数据保存到同一个 PostgreSQL 数据库。
作业本身使用 @EnableScheduling
安排,并且每 5 分钟由 cron 表达式触发:
@Scheduled(cron = "${job.assignment-rules}")
void processAssignments() {
try {
log.debug("Running assignment processing job");
jobLauncher.run(assignmentProcessingJob, populateJobParameters());
} catch (JobExecutionException e) {
log.error("Job processing has failed", e);
}
}
这是来自 application.yml
的 cron 表达式:
job:
assignment-rules: "0 0/5 * * * *"
问题是它在 运行 秒后停止安排(每次 运行 秒的数量不同)。让我们来看看 Spring 批处理模式:
select ex.job_instance_id, ex.create_time, ex.start_time, ex.end_time, ex.status, ex.exit_code, ex.exit_message
from batch_job_execution ex inner join batch_job_instance bji on ex.job_instance_id = bji.job_instance_id
order by start_time desc, job_instance_id desc;
然后沉默。日志中没有什么特别的。
我认为唯一有意义的是在该实例上还有两个作业 运行ning。其中之一非常耗时,因为它通过 SMTP 发送电子邮件。
整个工作时间表是:
job:
invitation-email: "0 0/10 * * * *"
assignment-rules: "0 0/5 * * * *"
rm-subordinates-count: "0 0/30 * * * *"
同事们,谁能指出我解决这个问题的方法?
非常感谢
使用默认 SyncTaskExecutor
启动作业在您的用例中并不安全,因为所有作业都将由单个线程执行。如果其中一项工作需要超过 5 分钟才能完成 运行,下一个工作将堆积起来并且在某个时候无法启动。
我会在您的用例中配置一个带有异步 TaskExecutor
实现(如 org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor
)的 JobLauncher
。您可以在 Configuring a JobLauncher 部分找到示例(参见 "Figure 3. Asynchronous Job Launcher Sequence")。
除了 Spring 批处理的 JobLauncher
使用的任务执行器配置之外,您还需要确保 Spring 使用正确的任务执行器启动计划任务(因为您使用的是 @EnableScheduling
)。详情请参阅Task Execution and Scheduling部分。
在一个项目中,我们必须 运行 一个定期启动的作业(现在在 QA env 上每 5 分钟一次)为 40k 用户处理一些分配。
我们决定使用 Spring Batch,因为它非常适合并使用几乎默认配置实现它(例如,它在引擎盖下使用 SyncTaskExecutor
)。
好的,所以,有一个作业由一个步骤组成:
- 开箱即用
HibernatePagingItemReader
- 在内存中执行轻量级计算的自定义
ItemProcessor
- 自定义
ItemWriter
通过多个 JPQL 和本机查询将数据保存到同一个 PostgreSQL 数据库。
作业本身使用 @EnableScheduling
安排,并且每 5 分钟由 cron 表达式触发:
@Scheduled(cron = "${job.assignment-rules}")
void processAssignments() {
try {
log.debug("Running assignment processing job");
jobLauncher.run(assignmentProcessingJob, populateJobParameters());
} catch (JobExecutionException e) {
log.error("Job processing has failed", e);
}
}
这是来自 application.yml
的 cron 表达式:
job:
assignment-rules: "0 0/5 * * * *"
问题是它在 运行 秒后停止安排(每次 运行 秒的数量不同)。让我们来看看 Spring 批处理模式:
select ex.job_instance_id, ex.create_time, ex.start_time, ex.end_time, ex.status, ex.exit_code, ex.exit_message
from batch_job_execution ex inner join batch_job_instance bji on ex.job_instance_id = bji.job_instance_id
order by start_time desc, job_instance_id desc;
job:
invitation-email: "0 0/10 * * * *"
assignment-rules: "0 0/5 * * * *"
rm-subordinates-count: "0 0/30 * * * *"
同事们,谁能指出我解决这个问题的方法?
非常感谢
使用默认 SyncTaskExecutor
启动作业在您的用例中并不安全,因为所有作业都将由单个线程执行。如果其中一项工作需要超过 5 分钟才能完成 运行,下一个工作将堆积起来并且在某个时候无法启动。
我会在您的用例中配置一个带有异步 TaskExecutor
实现(如 org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor
)的 JobLauncher
。您可以在 Configuring a JobLauncher 部分找到示例(参见 "Figure 3. Asynchronous Job Launcher Sequence")。
除了 Spring 批处理的 JobLauncher
使用的任务执行器配置之外,您还需要确保 Spring 使用正确的任务执行器启动计划任务(因为您使用的是 @EnableScheduling
)。详情请参阅Task Execution and Scheduling部分。