fix(cron): restore ShedLock DB-time for dialects that support it

The KingbaseES change removed usingDbTime() unconditionally, which made
every deployment (MySQL/H2/PostgreSQL) fall back to app-server time for
distributed lock timing — reintroducing node clock-drift risk in
multi-instance setups. Re-enable usingDbTime() for databases in ShedLock's
built-in dialect map and skip it only for KingbaseES, which is not covered
and would otherwise throw at lock acquisition.
This commit is contained in:
matevip 2026-06-14 10:44:32 +08:00
parent 25a83ad858
commit ed6eac310a

View File

@ -9,6 +9,7 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.JdbcTemplate;
import javax.sql.DataSource; import javax.sql.DataSource;
import java.sql.Connection;
/** /**
* RFC-03 Lane G2 distributed lock provider for the cron scheduler. * RFC-03 Lane G2 distributed lock provider for the cron scheduler.
@ -37,15 +38,38 @@ public class ShedLockConfig {
@Bean @Bean
public LockProvider lockProvider(DataSource dataSource) { public LockProvider lockProvider(DataSource dataSource) {
log.info("[ShedLock] Initializing JDBC LockProvider for cron scheduling"); boolean useDbTime = supportsDbTime(dataSource);
return new JdbcTemplateLockProvider( log.info("[ShedLock] Initializing JDBC LockProvider for cron scheduling (usingDbTime={})", useDbTime);
JdbcTemplateLockProvider.Configuration.Builder builder =
JdbcTemplateLockProvider.Configuration.builder() JdbcTemplateLockProvider.Configuration.builder()
.withJdbcTemplate(new JdbcTemplate(dataSource)) .withJdbcTemplate(new JdbcTemplate(dataSource))
.withTableName("shedlock") .withTableName("shedlock");
// usingDbTime() removed KingbaseES not in ShedLock's
// built-in dialect map; app-server time is sufficient // Server-side DB time (NOW()) avoids node clock drift across a
// given lockAtMostFor=PT30M // multi-instance deployment. ShedLock's built-in db-time dialect map
.build() // covers MySQL/MariaDB, PostgreSQL, H2, etc. KingbaseES is not in that
); // map, so usingDbTime() would throw there fall back to app-server
// time for it, which is safe given lockAtMostFor=PT30M.
if (useDbTime) {
builder.usingDbTime();
}
return new JdbcTemplateLockProvider(builder.build());
}
/**
* Returns true when the DataSource's database is covered by ShedLock's
* built-in db-time dialect map. Only KingbaseES is excluded; on any
* detection failure we conservatively return false so the lock provider
* never throws at acquisition time.
*/
private boolean supportsDbTime(DataSource dataSource) {
try (Connection connection = dataSource.getConnection()) {
String product = connection.getMetaData().getDatabaseProductName().toLowerCase();
return !product.contains("kingbase");
} catch (Exception e) {
log.warn("[ShedLock] Could not detect database product; using app-server time: {}", e.getMessage());
return false;
}
} }
} }