是否有在特定时间或应用程序重启后自动删除 LiquiBase DATABASE CHANGELOGLOCK 的配置?

Is there a configuration for removing LiquiBase DATABASE CHANGELOGLOCK automatically after a certain time or on app restart?

我们有 SpringBoot 2 驱动的 HA java 应用程序,我们在其中使用了 PostgreSQL。

由于某些原因,例如意外崩溃或异常,Liquibase 以一个从未发布过的陈旧 DATABASECHANGELOGLOCK 告终。

这会导致应用程序的后续部署失败,应用程序等待更改锁然后退出,如下所示:

   2020-03-04T11:10:31.78+0200 SELECT LOCKED FROM public.databasechangeloglock WHERE ID=1
   2020-03-04T11:10:31.78+0200 Waiting for changelog lock....
   2020-03-04T11:10:32.87+0200 SELECT LOCKED FROM public.databasechangeloglock WHERE ID=1
   2020-03-04T11:10:32.87+0200 Waiting for changelog lock....
   2020-03-04T11:10:41.78+0200 SELECT LOCKED FROM public.databasechangeloglock WHERE ID=1
   2020-03-04T11:10:41.78+0200 Waiting for changelog lock....
   2020-03-04T11:10:42.87+0200 SELECT LOCKED FROM public.databasechangeloglock WHERE ID=1
   2020-03-04T11:10:42.87+0200 Waiting for changelog lock....
   2020-03-04T11:10:51.79+0200 SELECT LOCKED FROM public.databasechangeloglock WHERE ID=1
   2020-03-04T11:10:51.79+0200 Waiting for changelog lock....
   2020-03-04T11:10:52.88+0200 SELECT LOCKED FROM public.databasechangeloglock WHERE ID=1
   2020-03-04T11:10:52.88+0200 Waiting for changelog lock....
   2020-03-04T11:10:54.00+0200 ERR 2020-03-04 09:10:54.010 UTC
   2020-03-04T11:10:55.88+0200 [HEALTH/0] ERR Failed to make TCP connection to port 8080: connection refused
   2020-03-04T11:10:55.88+0200 [CELL/0] ERR Failed after 1m0.626s: readiness health check never passed.
   2020-03-04T11:10:55.89+0200 [CELL/SSHD/0] OUT Exit status 0
   2020-03-04T11:10:55.89+0200 info    [native] Initiating shutdown sequence for Java agent
   2020-03-04T11:10:55.89+0200 info    [] Connection Status (120 times 300s)      : 0909

是否有用于在特定时间后自动删除 Liquibase DATABASECHANGELOGLOCK 或在应用程序启动时删除它的配置,如果它早于比方说 5 分钟或预定义的时间段。 或者这可以在 Postgres 开始寻找更改锁之前在 App Start 以编程方式完成。

所以我能够通过以下方法实现这一点:

我们使用 SpringLiquibase bean 初始化 LiquiBase。

在这个bean中,在构建Liquibase实例之前,我调用了一个方法,该方法使用语句查询数据库以获取锁,如果有超过5分钟的锁,我们将其删除。

 @Bean
 public SpringLiquibase liquibase(DataSource dataSource) {
        // Added a hook to check for locks before LiquiBase initialises.
        removeDBLock(dataSource);
        //
        SpringLiquibase liquibase = new SpringLiquibase();
        liquibase.setChangeLog(Constants.DDL_XML);
        liquibase.setDataSource(dataSource);
        return liquibase;
    }



 private void removeDBLock(DataSource dataSource) {
   
    //Timestamp, currently set to 5 mins or older.

    final Timestamp lastDBLockTime = new Timestamp(System.currentTimeMillis() - (5 * 60 * 1000));
    
    final String query = format("DELETE FROM DATABASECHANGELOGLOCK WHERE LOCKED=true AND LOCKGRANTED<'%s'", lastDBLockTime.toString());
    

    try (Statement stmt = dataSource.getConnection().createStatement()) {

        int updateCount = stmt.executeUpdate(query);
        if(updateCount>0){
            log.error("Locks Removed Count: {} .",updateCount);
        }
    } catch (SQLException e) {
        log.error("Error! Remove Change Lock threw and Exception. ",e);
    }
}

Liquibase 提供的默认锁定实现使用名为 'DATABASECHANGELOGLOCK' 的数据库 table。一旦获得锁的进程意外终止,恢复的唯一方法是手动释放该锁(使用 Liquibase CLI 或使用 SQL 语句)。请看一下这个 Liquibase 扩展,它通过使用数据库锁替换了 StandardLockService:https://github.com/blagerweij/liquibase-sessionlock

此扩展使用 MySQL 或 Postgres 用户锁定语句,当数据库连接关闭时(例如,当容器意外停止时),这些语句会自动释放。使用扩展所需的唯一事情是向库添加依赖项。 Liquibase 会自动检测改进后的 LockService

我不是图书馆的作者,但我在寻找解决方案时偶然发现了图书馆。我通过将库发布到 Maven Central 来帮助作者。目前支持 MySQL 和 PostgreSQL,但支持其他 RDBMS 应该相当容易。