fix: 完善分布式调度恢复与批量触发
- 持久化 Quartz refire 状态并收口运行时启动关闭顺序 - 增加批量 Trigger 获取配置、校验与回归测试
This commit is contained in:
@@ -53,6 +53,11 @@
|
||||
<artifactId>h2</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-jdbc</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
|
||||
@@ -18,6 +18,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.sql.init.dependency.DependsOnDatabaseInitialization;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@@ -61,6 +62,7 @@ public class EasyAgentsSchedulerAutoConfiguration {
|
||||
*/
|
||||
@Bean(name = SCHEDULER_BEAN_NAME, initMethod = "start", destroyMethod = "close")
|
||||
@ConditionalOnMissingBean(ScheduleService.class)
|
||||
@DependsOnDatabaseInitialization
|
||||
public QuartzScheduleService easyAgentsQuartzScheduleService(
|
||||
EasyAgentsSchedulerProperties properties,
|
||||
ListableBeanFactory beanFactory,
|
||||
@@ -83,6 +85,8 @@ public class EasyAgentsSchedulerAutoConfiguration {
|
||||
quartz.isClustered(),
|
||||
quartz.getThreadCount(),
|
||||
quartz.getThreadPriority(),
|
||||
quartz.getBatchTriggerAcquisitionMaxCount(),
|
||||
quartz.getBatchTriggerAcquisitionFireAheadTimeWindowMillis(),
|
||||
quartz.getClusterCheckinIntervalMillis(),
|
||||
quartz.getMisfireThresholdMillis(),
|
||||
quartz.isWaitForJobsToCompleteOnShutdown(),
|
||||
|
||||
@@ -104,6 +104,12 @@ public class EasyAgentsSchedulerProperties {
|
||||
/** Quartz Worker 线程优先级。 */
|
||||
private int threadPriority = Thread.NORM_PRIORITY;
|
||||
|
||||
/** 单次批量获取 Trigger 的最大数量。 */
|
||||
private int batchTriggerAcquisitionMaxCount = 1;
|
||||
|
||||
/** 可提前纳入批量的时间窗口,单位毫秒。 */
|
||||
private long batchTriggerAcquisitionFireAheadTimeWindowMillis;
|
||||
|
||||
/** 集群心跳间隔,单位毫秒。 */
|
||||
private long clusterCheckinIntervalMillis = 15_000L;
|
||||
|
||||
@@ -251,6 +257,45 @@ public class EasyAgentsSchedulerProperties {
|
||||
this.threadPriority = threadPriority;
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回单次批量获取 Trigger 的最大数量。
|
||||
*
|
||||
* @return 批量上限
|
||||
*/
|
||||
public int getBatchTriggerAcquisitionMaxCount() {
|
||||
return batchTriggerAcquisitionMaxCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置单次批量获取 Trigger 的最大数量。
|
||||
*
|
||||
* @param batchTriggerAcquisitionMaxCount 批量上限
|
||||
*/
|
||||
public void setBatchTriggerAcquisitionMaxCount(
|
||||
int batchTriggerAcquisitionMaxCount) {
|
||||
this.batchTriggerAcquisitionMaxCount = batchTriggerAcquisitionMaxCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回可提前纳入批量的时间窗口。
|
||||
*
|
||||
* @return 毫秒窗口
|
||||
*/
|
||||
public long getBatchTriggerAcquisitionFireAheadTimeWindowMillis() {
|
||||
return batchTriggerAcquisitionFireAheadTimeWindowMillis;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置可提前纳入批量的时间窗口。
|
||||
*
|
||||
* @param batchTriggerAcquisitionFireAheadTimeWindowMillis 毫秒窗口
|
||||
*/
|
||||
public void setBatchTriggerAcquisitionFireAheadTimeWindowMillis(
|
||||
long batchTriggerAcquisitionFireAheadTimeWindowMillis) {
|
||||
this.batchTriggerAcquisitionFireAheadTimeWindowMillis =
|
||||
batchTriggerAcquisitionFireAheadTimeWindowMillis;
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回集群心跳间隔。
|
||||
*
|
||||
|
||||
@@ -114,6 +114,47 @@ public class EasyAgentsSchedulerAutoConfigurationTest {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证调度器等待 Spring Boot 数据库脚本初始化完成后再启动。
|
||||
*/
|
||||
@Test
|
||||
public void shouldWaitForDatabaseInitializationBeforeStartingScheduler() throws Exception {
|
||||
JdbcDataSource dataSource = dataSource();
|
||||
Map<String, Object> properties = enabledProperties();
|
||||
properties.put("easy-agents.scheduler.data-source-bean-name", "schedulerDataSource");
|
||||
properties.put("spring.sql.init.mode", "always");
|
||||
properties.put(
|
||||
"spring.sql.init.schema-locations",
|
||||
"classpath:quartz-schema/h2-2.5.2.sql"
|
||||
);
|
||||
|
||||
SpringApplication application = new SpringApplication(AutoDiscoveryApplication.class);
|
||||
application.setWebApplicationType(WebApplicationType.NONE);
|
||||
application.setDefaultProperties(properties);
|
||||
application.addInitializers(applicationContext -> {
|
||||
GenericApplicationContext genericContext =
|
||||
(GenericApplicationContext) applicationContext;
|
||||
genericContext.registerBean(
|
||||
"schedulerDataSource",
|
||||
DataSource.class,
|
||||
() -> dataSource
|
||||
);
|
||||
});
|
||||
|
||||
try (ConfigurableApplicationContext context = application.run()) {
|
||||
assertNotNull(context.getBean(ScheduleService.class));
|
||||
try (
|
||||
Connection connection = dataSource.getConnection();
|
||||
Statement statement = connection.createStatement();
|
||||
ResultSet resultSet = statement.executeQuery(
|
||||
"SELECT COUNT(*) FROM QRTZ_SCHEDULER_STATE"
|
||||
)
|
||||
) {
|
||||
assertTrue(resultSet.next());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证多个 DataSource 未明确选择时启动失败并提供可操作信息。
|
||||
*/
|
||||
@@ -162,6 +203,13 @@ public class EasyAgentsSchedulerAutoConfigurationTest {
|
||||
properties.put("easy-agents.scheduler.quartz.instance-id", "NON_CLUSTERED");
|
||||
properties.put("easy-agents.scheduler.quartz.clustered", "false");
|
||||
properties.put("easy-agents.scheduler.quartz.thread-count", "2");
|
||||
properties.put(
|
||||
"easy-agents.scheduler.quartz.batch-trigger-acquisition-max-count", "2"
|
||||
);
|
||||
properties.put(
|
||||
"easy-agents.scheduler.quartz.batch-trigger-acquisition-fire-ahead-time-window-millis",
|
||||
"500"
|
||||
);
|
||||
properties.put("easy-agents.scheduler.quartz.misfire-threshold-millis", "1000");
|
||||
return properties;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user