I have recently upgraded my application to spring boot 3 and using the latest version of liquibase i.e. 4.22 After the upgrade, liquibase has stopped executing the changelogs & the DATABASECHANGELOG table is empty in the DB.
My application supports multiple tenants i.e. multiple DBs are created at runtime based on the subscription to the applciation and the liquibase changelog is ran once the DB is created.
public void addTenant(final String dbKey) {
log.info("Setting up tenant for - {}", dbKey);
String url = StringUtils.replace(dbUrl, defaultDbName, dbKey);
DataSource tenantDataSource = DataSourceBuilder.create()
.driverClassName(dbDriver)
.url(url)
.username(dbUser)
.password(dbPwd)
.build();
// Check that new connection is 'live'. If not - throw exception
try (Connection c = tenantDataSource.getConnection()) {
final SpringLiquibase liquibase = new SpringLiquibase();
liquibase.setResourceLoader(resourceLoader);
liquibase.setDataSource(tenantDataSource);
liquibase.setChangeLog(liquibaseProperties.getChangeLog());
liquibase.setContexts(liquibaseProperties.getContexts());
liquibase.afterPropertiesSet();
tenantRoutingDataSourceWrapper.addTargetDataSource(dbKey, new CustomDataSource(url, dbUser, dbPwd, dbDriver));
} catch (Exception ex) {
log.error("Unable to add new tenant - {}.", dbKey, ex);
throw new RuntimeException(GenericError.UNSPECIFIC);
}
}
I tried downgrading the liquibase version and somehow it works till 4.20 version. All the version higher than 4.21 has this issue.
After a bit of digging finally found out the root cause of this issue. The Liquibase update command was not getting executed as Liquibase introduced a "fast check" cache to minimize the run of the changeset.
In the logs, I found these two statements:
In the
AbstractUpdateCommandStepclass, a new methodisUpToDateFastCheckis introduced for the fast check.The API doc is as follows:
This method checks for any existing key in the cache and returns true if it exists.
In my case, when the Liquibase runs for multiple DBs in the same instance, the same cache key was used (i.e. '/()'), and hence the changeset was not executed.
As a fix, added a label (i.e.
setLabelFilter()) for each DB so that it creates a unique cache key.