想法是,如果已经运行相同的作业,则不要启动作业。
作业资源管理器是简单注入到类中,其中是用于运行的计划方法
public class JobClass {
private final Job job;
private final JobExplorer jobExplorer;
private final JobLauncher jobLauncher;
public JobMain(Job job,
JobLauncher jobLauncher,
JobExplorer jobExplorer) {
this.job = job;
this.jobLauncher = jobLauncher;
this.jobExplorer = jobExplorer;
}
然后它被执行
@Scheduled("0 */5 * ? * *")
public void startJob() {
JobParameters jobParameters = new JobParametersBuilder()
.addString("jobName", String.valueOf(instant.toEpochMilli()))
.toJobParameters();
jobLauncher.run(job, jobParameters);
}
这不是解决方案,因为如果JVM在作业运行时停止,这将与当前作业运行相同:
jobExplorer.findRunningJobExecutions("jobName")
它将找到所有带有exitCode的作业ExitStatus.UNKNOWN.
在我看来,有3种解决方案:
解决方案一:
停止以前运行的未完成作业并运行新作业PROS:一切都干净,只有一个属性
续:失去当前作业的当前执行
@Scheduled("0 */5 * ? * *")
public void startJob() {
(JobExecution jobExecution: jobExplorer.findRunningJobExecutions("jobName")) jobExecution.stop();
...
}
解决方案2
计算最近运行的作业之间的时间,如这里所述,如果有任何不启动新作业:https://stackoverflow.com/a/23218986/1182625
优点:一切都很干净
CONT:必须有两倍的属性(5*60*1000和“0*/5 * ? * *")
Set<JobExecution> jobExecutions = jobExplorer.findRunningJobExecutions("jobName");
if(jobExecutions.size()>1){
Long currentTime = (new Date()).getTime();
for(JobExecution execution : jobExecutions) {
if((currentTime - execution.getStartTime().getTime()) < 5*60*1000) {
return;
} else {
execution.stop();
}
}
}
解决方案3
想法很简单,添加静态(在类的实例之间共享)易失性(在线程之间共享)标志,它将指示当前运行PROS的任何作业:只有一个属性
CONT:需要2个侦听器,以及不知道在多节点环境中反应如何的易失性静态变量
private static volatile boolean FINISHED = true;
然后简单添加监听器并完成修改方法:
// reset FINISHED after job is done
@AfterJob
public void afterJob() {
FINISHED = true;
}
public void setFinished() {
this.FINISHED = true;
}
简单地添加:
@Scheduled("0 */5 * ? * *")
public void startJob() {
if(!FINISHED) return;
FINISHED = false;
...
}
最后添加StepListener
public MyStepListener() {
...
@AfterStep
public ExitStatus afterStep(StepExecution stepExecution) {
if(stepExecution.getExitStatus().getExitCode().equalsIgnoreCase(ExitStatus.FAILED.getExitCode())) (new JobMain()).setFinished();
return null;
}
想法是,如果已经运行相同的作业,则不要启动作业。
根据设计,Spring Batch将阻止这种情况。如果您尝试在同一作业实例正在运行的作业执行时启动它,您将获得一个JobExecutionAlreadyRunningException
。
好吧,我想我走得很远,可能是KISS。
保持简单
所以,要实现这一点,如果您想使用属性文件中的值,可以简单地将fixedDelay或fixedStringDelay放在@Scheduled注释中。
@Scheduled(initialDelay = 3*60*1000, fixedDelayString ="${job.fixed_delay}")
这样我就实现了在同一时间我不会有一个以上相同工作的实例。我只在特定时间(如午夜或凌晨)丢掉工作...)
我试图从步骤(实现接口Tasklet的类的execute方法)内部启动作业。 显然我收到了例外 Java语言lang.IllegalStateException:在JobRepository中检测到现有事务 如何使Spring批处理步骤不是事务性的? 有人能解决我从一步内启动工作的主要需求吗? 提前感谢您的帮助!
我有一个spring批处理作业,从CSV文件读取并写入数据库。我想让它重新启动。例如,如果在读取文件或写入db时出现异常,导致作业失败,则应从失败的同一点/块重新开始,而不是从头开始读取整个文件。 我正在从一个endpoint触发作业启动器,并在我的控制器中配置了它。 目前,我正在通过控制器将参数(这是一个唯一的标识符/数字)传递给作业参数,以运行新的作业实例。如果作业失败,我将使用与GET请求中
在我的应用程序中,我有一个显示某种级别的列表视图。 我用资产中的一个文件填充listview。我在资产中的文件如下所示: 我的listview显示级别,当我单击listview的某个项目转到另一个活动时,“转到下一个活动”也会显示我的问题和选项。一切正常,我的问题是,当在第二个活动中按后退按钮转到第一个活动时,第一个活动再次启动,我的onCreate方法再次运行,我的listview项增加。(例如
我遵循了spring批处理文档,无法异步运行我的作业。 因此,我从一个web容器运行该作业,该作业将通过RESTendpoint触发。 我想让JobInstance ID在完成整个作业之前传递它作为响应。因此,他们可以稍后使用JobInstance ID检查作业的状态,而不是等待。但我没能让它工作。下面是我尝试过的示例代码。请让我知道我错过了什么或错了什么。 BatchConfig创建异步JobL
我已经将我的Spring批处理配置为每当通过API调用从UI发出请求时触发作业。我面临的问题是,该作业仅在第一次和其他尝试时工作正常,每当调用时,作业不会以预期的方式响应。似乎他们正在尝试恢复,但我想再次重新启动整个执行。感谢您提前提供的任何帮助。 主要的班 配置班 JobListener.class 我的听众。班 Controller.class 应用属性 首次发出API请求时的响应 其他时间的