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 javax.sql.DataSource;
import java.sql.Connection;
/**
* RFC-03 Lane G2 distributed lock provider for the cron scheduler.
@ -37,15 +38,38 @@ public class ShedLockConfig {
@Bean
public LockProvider lockProvider(DataSource dataSource) {
log.info("[ShedLock] Initializing JDBC LockProvider for cron scheduling");
return new JdbcTemplateLockProvider(
boolean useDbTime = supportsDbTime(dataSource);
log.info("[ShedLock] Initializing JDBC LockProvider for cron scheduling (usingDbTime={})", useDbTime);
JdbcTemplateLockProvider.Configuration.Builder builder =
JdbcTemplateLockProvider.Configuration.builder()
.withJdbcTemplate(new JdbcTemplate(dataSource))
.withTableName("shedlock")
// usingDbTime() removed KingbaseES not in ShedLock's
// built-in dialect map; app-server time is sufficient
// given lockAtMostFor=PT30M
.build()
);
.withTableName("shedlock");
// Server-side DB time (NOW()) avoids node clock drift across a
// multi-instance deployment. ShedLock's built-in db-time dialect map
// 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;
}
}
}