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

故事扮演 提交于 2021-02-04 21:50:05

问题


We have SpringBoot 2 driven HA java application in which we use PostgreSQL underneath.

For certain reasons like unexpected crashes or Exceptions, Liquibase ends up with a stale DATABASECHANGELOGLOCK which was never released.

This results in subsequent deployments of the app failing with app waiting for the change lock and then exiting as follows:

   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

Is there a configuration for removing Liquibase DATABASECHANGELOGLOCK automatically after a certain time or removing it on application start if it is older than let's say 5 mins or a predefined time period. Or can this be done programatically at App Start before Postgres starts looking for the change lock.


回答1:


So I was able to achieve this via the following approach:

We initialise LiquiBase using a SpringLiquibase bean.

Within this bean, before the Liquibase instance is constructed, I called a method which uses Statements to query the database for a lock, and if there are any locks older than 5 minutes, we delete them.

 @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);
    }
}



回答2:


The default lock implementation provided by Liquibase uses a database table called 'DATABASECHANGELOGLOCK'. Once a process that has acquired the lock is unexpectedly terminated, the only way to recover is to manually release that lock (using the Liquibase CLI or using a SQL statement). Please take a look at this Liquibase extension, which replaces the StandardLockService, by using database locks: https://github.com/blagerweij/liquibase-sessionlock

This extension uses MySQL or Postgres user lock statements, which are automatically released when the database connection is closed (e.g. when the container is stopped unexpectedly). The only thing required to use the extension is to add a dependency to the library. Liquibase will automatically detect the improved LockService.

I'm not the author of the library, but I stumbled upon the library when I was searching for a solution. I helped the author by releasing the library to Maven central. Currently supports MySQL and PostgreSQL, but should be fairly easy to support other RDBMS.



来源:https://stackoverflow.com/questions/63254808/is-there-a-configuration-for-removing-liquibase-database-changeloglock-automatic

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!