我有一个springboot/spring批处理应用程序,它启动不同的作业。
当应用程序停止时( CTRL-C
)作业保持在运行状态(已启动)。
尽管 CTRL-C
让应用程序有足够的时间优雅地停止作业结果与 kill -9
.
我找到了一种方法(见下文),可以在应用程序被终止时优雅地停止所有作业 CTRL-C
,但想知道是否有更好/更简单的方法来实现这一目标。
下面的所有内容都是关于我如何设法停止工作的文档。
在一篇来自부알프레도 一 JobExecutionListener
用于注册应停止作业的关闭挂钩:
public class ProcessShutdownListener implements JobExecutionListener {
private final JobOperator jobOperator;
ProcessShutdownListener(JobOperator jobOperator) { this.jobOperator = jobOperator; }
@Override public void afterJob(JobExecution jobExecution) { /* do nothing. */ }
@Override
public void beforeJob(final JobExecution jobExecution) {
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
super.run();
try {
jobOperator.stop(jobExecution.getId());
while(jobExecution.isRunning()) {
try { Thread.sleep(100); } catch (InterruptedException e) {}
}
} catch (NoSuchJobExecutionException | JobExecutionNotRunningException e) { /* ignore */ }
}
});
}
}
除了提供的代码,我还必须创建一个 JobRegistryBeanPostProcessor
.
没有这个后处理器 jobOperator
找不到工作。
( NoSuchJobException: No job configuration with the name [job1] was registered
```
@Bean
public JobRegistryBeanPostProcessor jobRegistryBeanPostProcessor(JobRegistry jobRegistry) {
JobRegistryBeanPostProcessor postProcessor = new JobRegistryBeanPostProcessor();
postProcessor.setJobRegistry(jobRegistry);
return postProcessor;
}
关闭挂钩无法将状态写入数据库,因为数据库连接已关闭: `org.h2.jdbc.JdbcSQLNonTransientConnectionException: Database is already closed (to disable automatic closing at VM shutdown, add ";DB_CLOSE_ON_EXIT=FALSE" to the db URL)` ```
Processing item 2 before
Shutdown Hook is running !
2021-02-08 22:39:48.950 INFO 12676 --- [extShutdownHook] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown initiated...
2021-02-08 22:39:49.218 INFO 12676 --- [extShutdownHook] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown completed.
Processing item 3 before
Exception in thread "Thread-3" org.springframework.transaction.CannotCreateTransactionException: Could not open JDBC Connection for transaction; nested exception is java.sql.SQLTransientConnectionException: HikariPool-1 - Connection is not available, request timed out after 30004ms.
为了确保springboot在停止作业之前不会关闭hikari数据源池,我使用了 SmartLifeCycle
正如这里提到的。
决赛 ProcessShutdownListener
看起来像:
@Component
public class ProcessShutdownListener implements JobExecutionListener, SmartLifecycle {
private final JobOperator jobOperator;
public ProcessShutdownListener(JobOperator jobOperator) { this.jobOperator = jobOperator; }
@Override
public void afterJob(JobExecution jobExecution) { /* do nothing. */ }
private static final List<Runnable> runnables = new ArrayList<>();
@Override
public void beforeJob(final JobExecution jobExecution) {
runnables.add(() -> {
try {
if (!jobOperator.stop(jobExecution.getId())) return;
while (jobExecution.isRunning()) {
try {
Thread.sleep(100);
} catch (InterruptedException ignored) { /* ignore */ }
}
} catch (NoSuchJobExecutionException | JobExecutionNotRunningException e) { /* ignore */ }
});
}
@Override
public void start() {}
@Override
public void stop() {
// runnables.stream()
// .parallel()
// .forEach(Runnable::run);
runnables.forEach(Runnable::run);
}
@Override
public boolean isRunning() { return true; }
@Override
public boolean isAutoStartup() { return true; }
@Override
public void stop(Runnable callback) { stop(); callback.run(); }
@Override
public int getPhase() { return Integer.MAX_VALUE; }
}
配置作业时必须注册此侦听器:
@Bean
public Job job(JobBuilderFactory jobs,
ProcessShutdownListener processShutdownListener) {
return jobs.get("job1")
.listener(processShutdownListener)
.start(step(null))
.build();
}
最后,如异常输出中所述,输出标志: ;DB_CLOSE_ON_EXIT=FALSE
必须添加到jdbc url。
1条答案
按热度按时间5m1hhzi41#
这种方法是可行的,因为据我所知,关闭钩子是jvm提供的截获外部信号的唯一方法。但是,这种方法不能保证工作,因为jvm不能保证调用关闭挂钩。下面是一段摘自javadoc的
Runtime.addShutdownHook
方法:此外,关闭挂钩预计将“快速”运行:
就你而言,
JobOperator.stop
涉及一个数据库事务(可能跨网络)来更新作业的状态,我不确定这个操作是否足够快。作为补充说明,在samples模块中有一个名为gracefulshutdownfunctionaltests的示例。这个例子基于
JobExecution.stop
已弃用,但将更新为使用JobOperator.stop
.