Friday, December 31, 2021

Getting rid of Liquibase changelog lock

If you're using Liquibase you most probably faced the DB changelog lock. The Liquibase documentation describes it as:

Liquibase uses the DATABASECHANGELOGLOCK table to ensure only one instance of Liquibase is running at one time.

Because Liquibase simply reads from the DATABASECHANGELOG table to determine which changesets need to run, if multiple instances of Liquibase are executed against the same database concurrently you will get conflicts. This can happen if multiple developers use the same database instance or if there are multiple servers in a cluster which auto-run Liquibase on startup.

To get rid of the log you can start liquibase releaseLocks which in turn runs UPDATE DATABASECHANGELOGLOCK SET LOCKED=0 on DB level.

In theory you can disable the lock using https://github.com/liquibase/liquibase-nochangeloglock, but that is dangerous if you have several instances of your app/service runing in parallel.

There are cases where the lock gets in the way and you want to automate its release. Several pending PRs are with Liquibase at this moment (December 2021) that will make this lock bound to a particular process. Until these are merged however, your best option would be to use a Liquibase extension like https://github.com/oridool/liquibase-locking. This particular extension seems to be bound to PostgreSQL and in my case I was using different DB.

I wanted to keep the locking to prevent accidental changelog modified from two instances at the same time. But also I had to work with the following set of boundary conditions:

  • only one instance of your service/application is usually running (monolith or scheduled task for instance)
  • application is often killed or exits during startup, while applying Liquibase changelog  
  • PaaS health check or probe (K8s, Messos/Marathon, Cloud Foundry) does not allow Liquibase changelog changes to run more than a certain amount of time

So I decided to create a Liquibase extension that: 

  • releases the lock if it was created more than max-timeout minutes ago
  • works with the default strategy (waits for the lock) otherwise
 
Be aware that you can only safely use it if you have one instance of your application and it cannot run for more that the configured max timeout.

id_rsa.pub: invalid format, error in libcrypto

After I upgraded my Linux and got Python 3.10 by default, it turned out that Ansible 2.9 will no longer run and is unsupported together with...