blagerweij / liquibase-sessionlock Goto Github PK
View Code? Open in Web Editor NEWSession-level lock support for Liquibase
License: Apache License 2.0
Session-level lock support for Liquibase
License: Apache License 2.0
Last week I ran into the problem of DATABASECHANGELOGLOCK
getting stuck, and a service failing to restart, because Liquibase times out waiting for the lock. The service is running on Kubernetes with multiple replicas, a replica was restarted by the system, which is normal in Kubernetes, and for some reason it terminated in the middle of checking Liquibase change log, leaving the lock in the DB, so after that no new replicas could start.
I started to look for solutions to this, and this library seems like the perfect solution for the problem. I created a test scenario to reproduce the error I ran into. At first adding the dependency seemed to resolve the issue as expected, but on the second run a change set I added for testing that runs slow on purpose was applied twice by two different replicas.
Spring Boot: 2.5.8
Liquibase: 4.3.5
liquibase-sessionlock: 1.6.3
mysql-connector-java: 8.0.27
MySQL: 5.7.42
3
replicas, with Recreate
strategy, which means, all 3 replicas will start at the same time, and wait for the 3 replicas to start successfullyWhithout liquibase-sessionlock the lock in DATABASECHANGELOGLOCK
got stuck, so no replicas could start successfully, so I could reproduce the problem.
I deleted the slow change set from the DATABASECHANGELOG
table, added the liquibase-sessionlock dependency, and deployed a new version.
After adding liquibase-sessionlock when the replica that started the migration was terminated, the other two replicas tried to acquire the session lock, both saw that it was successful, both read the DATABASECHANGELOG
table, then one of them returned to wait for the lock, the other applied the change set, and released the lock, the first one acquired the lock again, and applied the same change set, then released the lock, the third replica that started after the termination, acquired the lock, did not apply any changes and then released the lock.
select sleep(120);
The first replica, that was terminated:
INFO 2023-08-29T11:04:51.853Z HikariPool-1 - Starting...
INFO 2023-08-29T11:04:52.315Z HikariPool-1 - Start completed.
INFO 2023-08-29T11:04:52.685Z Successfully acquired change log lock
INFO 2023-08-29T11:04:55.101Z Reading from rfid.DATABASECHANGELOG
INFO 2023-08-29T11:04:55.333Z Successfully released change log lock
INFO 2023-08-29T11:04:55.359Z Successfully acquired change log lock
INFO 2023-08-29T11:04:55.360552323Z Skipping auto-registration
WARNING 2023-08-29T11:04:55.361Z Skipping auto-registration
WARNING 2023-08-29T11:06:02.194Z HikariPool-1 - Connection com.mysql.cj.jdbc.ConnectionImpl@45e22def marked as broken because of SQLSTATE(08S01), ErrorCode(0) com.mysql.cj.jdbc.exceptions.CommunicationsException: Communications link failure The last packet successfully received from the server was 66,750 milliseconds ago. The last packet sent successfully to the server was 66,769 milliseconds ago. at com.mysql.cj.jdbc.exceptions.SQLError.createCommunicationsException(SQLError.java:174) at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:64) at com.mysql.cj.jdbc.StatementImpl.executeInternal(StatementImpl.java:768) at com.mysql.cj.jdbc.StatementImpl.execute(StatementImpl.java:653) at com.zaxxer.hikari.pool.ProxyStatement.execute(ProxyStatement.java:94) at com.zaxxer.hikari.pool.HikariProxyStatement.execute(HikariProxyStatement.java) at liquibase.executor.jvm.JdbcExecutor$ExecuteStatementCallback.doInStatement(JdbcExecutor.java:389) at liquibase.executor.jvm.JdbcExecutor.execute(JdbcExecutor.java:82) at liquibase.executor.jvm.JdbcExecutor.execute(JdbcExecutor.java:150) at liquibase.database.AbstractJdbcDatabase.execute(AbstractJdbcDatabase.java:1278) at liquibase.database.AbstractJdbcDatabase.executeStatements(AbstractJdbcDatabase.java:1260) at liquibase.changelog.ChangeSet.execute(ChangeSet.java:637) at liquibase.changelog.visitor.UpdateVisitor.visit(UpdateVisitor.java:49) at liquibase.changelog.ChangeLogIterator$2.lambda$null$0(ChangeLogIterator.java:111) at liquibase.Scope.lambda$child$0(Scope.java:160) at liquibase.Scope.child(Scope.java:169) at liquibase.Scope.child(Scope.java:159) at liquibase.Scope.child(Scope.java:138) at liquibase.changelog.ChangeLogIterator$2.lambda$run$1(ChangeLogIterator.java:110) at liquibase.Scope.lambda$child$0(Scope.java:160) at liquibase.Scope.child(Scope.java:169) at liquibase.Scope.child(Scope.java:159) at liquibase.Scope.child(Scope.java:138) at liquibase.Scope.child(Scope.java:222) at liquibase.changelog.ChangeLogIterator$2.run(ChangeLogIterator.java:94) at liquibase.Scope.lambda$child$0(Scope.java:160) at liquibase.Scope.child(Scope.java:169) at liquibase.Scope.child(Scope.java:159) at liquibase.Scope.child(Scope.java:138) at liquibase.Scope.child(Scope.java:222) at liquibase.Scope.child(Scope.java:226) at liquibase.changelog.ChangeLogIterator.run(ChangeLogIterator.java:66) at liquibase.Liquibase.lambda$null$0(Liquibase.java:272) at liquibase.Scope.lambda$child$0(Scope.jav…
WARNING 2023-08-29T11:06:02.260Z Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'liquibase' defined in class path resource [org/springframework/boot/autoconfigure/liquibase/LiquibaseAutoConfiguration$LiquibaseConfiguration.class]: Invocation of init method failed; nested exception is liquibase.exception.DatabaseException: java.sql.SQLException: Connection is closed
INFO 2023-08-29T11:06:02.263Z HikariPool-1 - Shutdown initiated...
INFO 2023-08-29T11:06:02.530Z HikariPool-1 - Shutdown completed.
WARNING 2023-08-29T11:06:02.681Z Invocation of destroy method failed on bean with name 'reactorServerResourceFactory': java.lang.NullPointerException: Cannot invoke "org.springframework.cloud.sleuth.CurrentTraceContext.context()" because the return value of "org.springframework.cloud.sleuth.internal.LazyBean.get()" is null
The second replica, that took over first, and applied the change set:
INFO 2023-08-29T11:05:15.978Z HikariPool-1 - Starting...
INFO 2023-08-29T11:05:16.893Z HikariPool-1 - Start completed.
INFO 2023-08-29T11:05:22.861Z Waiting for changelog lock....
INFO 2023-08-29T11:05:32.878Z Waiting for changelog lock....
INFO 2023-08-29T11:05:42.898Z Waiting for changelog lock....
INFO 2023-08-29T11:05:52.915Z Waiting for changelog lock....
INFO 2023-08-29T11:06:02.931Z Waiting for changelog lock....
INFO 2023-08-29T11:06:07.947Z Successfully acquired change log lock
INFO 2023-08-29T11:06:10.489Z Reading from rfid.DATABASECHANGELOG
INFO 2023-08-29T11:06:10.705Z Successfully released change log lock
INFO 2023-08-29T11:06:13.385Z Successfully acquired change log lock
WARNING 2023-08-29T11:06:13.385Z Skipping auto-registration
INFO 2023-08-29T11:06:13.392805017Z Skipping auto-registration
INFO 2023-08-29T11:08:13.512Z SQL in file db/V1_31_DELETEME_test_liquibase_session_lock.sql executed
INFO 2023-08-29T11:08:13.528Z ChangeSet db/liquibase-changelog.xml::31::mate.sebestyen ran successfully in 120096ms
INFO 2023-08-29T11:08:13.657Z Successfully released change log lock
INFO 2023-08-29T11:08:14.127Z HHH000204: Processing PersistenceUnitInfo [name: default]
INFO 2023-08-29T11:08:14.347Z HHH000412: Hibernate ORM core version 5.4.33
INFO 2023-08-29T11:08:14.824Z HCANN000001: Hibernate Commons Annotations {5.1.2.Final}
INFO 2023-08-29T11:08:15.155Z HHH000400: Using dialect: org.hibernate.dialect.MySQL5InnoDBDialect
INFO 2023-08-29T11:08:18.589Z HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]
INFO 2023-08-29T11:08:18.615Z Initialized JPA EntityManagerFactory for persistence unit 'default'
The third replica, that applied the change set again:
INFO 2023-08-29T11:05:17.652Z HikariPool-1 - Starting...
INFO 2023-08-29T11:05:18.644Z HikariPool-1 - Start completed.
INFO 2023-08-29T11:05:24.182Z Waiting for changelog lock....
INFO 2023-08-29T11:05:34.202Z Waiting for changelog lock....
INFO 2023-08-29T11:05:44.219Z Waiting for changelog lock....
INFO 2023-08-29T11:05:54.236Z Waiting for changelog lock....
INFO 2023-08-29T11:06:04.255Z Waiting for changelog lock....
INFO 2023-08-29T11:06:10.703Z Successfully acquired change log lock
INFO 2023-08-29T11:06:13.105Z Reading from rfid.DATABASECHANGELOG
INFO 2023-08-29T11:06:13.382Z Successfully released change log lock
INFO 2023-08-29T11:06:18.430Z Waiting for changelog lock....
INFO 2023-08-29T11:06:28.446Z Waiting for changelog lock....
INFO 2023-08-29T11:06:38.465Z Waiting for changelog lock....
INFO 2023-08-29T11:06:48.480Z Waiting for changelog lock....
INFO 2023-08-29T11:06:58.495Z Waiting for changelog lock....
INFO 2023-08-29T11:07:08.511Z Waiting for changelog lock....
INFO 2023-08-29T11:07:18.527Z Waiting for changelog lock....
INFO 2023-08-29T11:07:28.547Z Waiting for changelog lock....
INFO 2023-08-29T11:07:38.563Z Waiting for changelog lock....
INFO 2023-08-29T11:07:48.578Z Waiting for changelog lock....
INFO 2023-08-29T11:07:58.596Z Waiting for changelog lock....
INFO 2023-08-29T11:08:08.611Z Waiting for changelog lock....
INFO 2023-08-29T11:08:13.663Z Successfully acquired change log lock
INFO 2023-08-29T11:08:13.666923296Z Skipping auto-registration
WARNING 2023-08-29T11:08:13.669Z Skipping auto-registration
INFO 2023-08-29T11:10:13.809Z SQL in file db/V1_31_DELETEME_test_liquibase_session_lock.sql executed
INFO 2023-08-29T11:10:13.824Z ChangeSet db/liquibase-changelog.xml::31::mate.sebestyen ran successfully in 120115ms
INFO 2023-08-29T11:10:13.978Z Successfully released change log lock
INFO 2023-08-29T11:10:14.399Z HHH000204: Processing PersistenceUnitInfo [name: default]
INFO 2023-08-29T11:10:14.584Z HHH000412: Hibernate ORM core version 5.4.33
INFO 2023-08-29T11:10:14.999Z HCANN000001: Hibernate Commons Annotations {5.1.2.Final}
INFO 2023-08-29T11:10:15.320Z HHH000400: Using dialect: org.hibernate.dialect.MySQL5InnoDBDialect
INFO 2023-08-29T11:10:18.753Z HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]
INFO 2023-08-29T11:10:18.776Z Initialized JPA EntityManagerFactory for persistence unit 'default'
The last replica, that was created, because of the termination:
INFO 2023-08-29T11:06:33.037Z HikariPool-1 - Starting...
INFO 2023-08-29T11:06:33.563Z HikariPool-1 - Start completed.
INFO 2023-08-29T11:06:39.004Z Waiting for changelog lock....
INFO 2023-08-29T11:06:49.019Z Waiting for changelog lock....
INFO 2023-08-29T11:06:59.039Z Waiting for changelog lock....
INFO 2023-08-29T11:07:09.057Z Waiting for changelog lock....
INFO 2023-08-29T11:07:19.074Z Waiting for changelog lock....
INFO 2023-08-29T11:07:29.092Z Waiting for changelog lock....
INFO 2023-08-29T11:07:39.108Z Waiting for changelog lock....
INFO 2023-08-29T11:07:49.126Z Waiting for changelog lock....
INFO 2023-08-29T11:07:59.146Z Waiting for changelog lock....
INFO 2023-08-29T11:08:09.165Z Waiting for changelog lock....
INFO 2023-08-29T11:08:19.185Z Waiting for changelog lock....
INFO 2023-08-29T11:08:29.203Z Waiting for changelog lock....
INFO 2023-08-29T11:08:39.220Z Waiting for changelog lock....
INFO 2023-08-29T11:08:49.238Z Waiting for changelog lock....
INFO 2023-08-29T11:08:59.254Z Waiting for changelog lock....
INFO 2023-08-29T11:09:09.271Z Waiting for changelog lock....
INFO 2023-08-29T11:09:19.287Z Waiting for changelog lock....
INFO 2023-08-29T11:09:29.304Z Waiting for changelog lock....
INFO 2023-08-29T11:09:39.324Z Waiting for changelog lock....
INFO 2023-08-29T11:09:49.340Z Waiting for changelog lock....
INFO 2023-08-29T11:09:59.357Z Waiting for changelog lock....
INFO 2023-08-29T11:10:09.373Z Waiting for changelog lock....
INFO 2023-08-29T11:10:14.390Z Successfully acquired change log lock
INFO 2023-08-29T11:10:16.502Z Reading from rfid.DATABASECHANGELOG
INFO 2023-08-29T11:10:16.740Z Successfully released change log lock
INFO 2023-08-29T11:10:16.760Z Successfully acquired change log lock
INFO 2023-08-29T11:10:16.763864829Z Skipping auto-registration
WARNING 2023-08-29T11:10:16.766Z Skipping auto-registration
INFO 2023-08-29T11:10:16.803Z Successfully released change log lock
INFO 2023-08-29T11:10:17.221Z HHH000204: Processing PersistenceUnitInfo [name: default]
INFO 2023-08-29T11:10:17.506Z HHH000412: Hibernate ORM core version 5.4.33
INFO 2023-08-29T11:10:18.172Z HCANN000001: Hibernate Commons Annotations {5.1.2.Final}
INFO 2023-08-29T11:10:18.556Z HHH000400: Using dialect: org.hibernate.dialect.MySQL5InnoDBDialect
INFO 2023-08-29T11:10:21.790Z HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]
INFO 2023-08-29T11:10:21.822Z Initialized JPA EntityManagerFactory for persistence unit 'default'
I believe this library could be the ideal solution for the initial problem, but there seems to be a concurrency issue, and the lock can somehow be acquired by two replicas at the same time, and both can read the DATABASECHANGELOG
table, to determine which change sets to apply.
Any help is appreciated, I'll try to find the issue, and submit a PR, if I'm successful.
org.owasp:dependency-check-maven reports Vulnerability in latest version of liquibase-sessionlock
liquibase-sessionlock-1.6.4.jar (pkg:maven/com.github.blagerweij/[email protected], cpe:2.3:a:liquibase:liquibase:1.6.4:::::::*) : CVE-2022-0839
mvn -V dependency-check:aggregate -Pvulnerability-check
I'm using Spring Boot 3 with Liquibase and liquibase-sessionlock
. It works well.
Then I'm trying to build a Spring Native docker image as described here: https://docs.spring.io/spring-boot/docs/current/reference/html/native-image.html#native-image.developing-your-first-application.buildpacks.gradle
The image is built successfully.
But when I run it an NPE error occurs:
2023-03-22T17:07:26.914Z ERROR 1 --- [ main] o.s.boot.SpringApplication : Application run failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'liquibase': java.lang.NullPointerException
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1762) ~[org.myapp.MyApplication:6.0.6]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:599) ~[org.myapp.MyApplication:6.0.6]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:521) ~[org.myapp.MyApplication:6.0.6]
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:326) ~[org.myapp.MyApplication:6.0.6]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[org.myapp.MyApplication:6.0.6]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:324) ~[org.myapp.MyApplication:6.0.6]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200) ~[org.myapp.MyApplication:6.0.6]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:313) ~[org.myapp.MyApplication:6.0.6]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200) ~[org.myapp.MyApplication:6.0.6]
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1132) ~[org.myapp.MyApplication:6.0.6]
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:907) ~[org.myapp.MyApplication:6.0.6]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:584) ~[org.myapp.MyApplication:6.0.6]
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146) ~[org.myapp.MyApplication:3.0.4]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:732) ~[org.myapp.MyApplication:3.0.4]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:434) ~[org.myapp.MyApplication:3.0.4]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:310) ~[org.myapp.MyApplication:3.0.4]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1304) ~[org.myapp.MyApplication:3.0.4]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1293) ~[org.myapp.MyApplication:3.0.4]
at org.myapp.MyApplication.main(MyApplication.java:12) ~[org.myapp.MyApplication:na]
Caused by: liquibase.exception.LiquibaseException: java.lang.NullPointerException
at liquibase.Liquibase.runInScope(Liquibase.java:2452) ~[na:na]
at liquibase.Liquibase.update(Liquibase.java:236) ~[na:na]
at liquibase.Liquibase.update(Liquibase.java:221) ~[na:na]
at liquibase.integration.spring.SpringLiquibase.performUpdate(SpringLiquibase.java:328) ~[org.myapp.MyApplication:na]
at liquibase.integration.spring.SpringLiquibase.afterPropertiesSet(SpringLiquibase.java:283) ~[org.myapp.MyApplication:na]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1808) ~[org.myapp.MyApplication:6.0.6]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1758) ~[org.myapp.MyApplication:6.0.6]
... 18 common frames omitted
Caused by: java.lang.NullPointerException: null
at [email protected]/java.lang.reflect.Method.invoke(Method.java:561) ~[org.myapp.MyApplication:na]
at com.github.blagerweij.sessionlock.SessionLockService.lambda$static$1(SessionLockService.java:257) ~[org.myapp.MyApplication:na]
at com.github.blagerweij.sessionlock.SessionLockService.getLog(SessionLockService.java:267) ~[org.myapp.MyApplication:na]
at com.github.blagerweij.sessionlock.SessionLockService.acquireLock(SessionLockService.java:156) ~[org.myapp.MyApplication:na]
at com.github.blagerweij.sessionlock.SessionLockService.waitForLock(SessionLockService.java:77) ~[org.myapp.MyApplication:na]
at liquibase.Liquibase.lambda$update$1(Liquibase.java:239) ~[na:na]
at liquibase.Scope.lambda$child$0(Scope.java:180) ~[org.myapp.MyApplication:na]
at liquibase.Scope.child(Scope.java:189) ~[org.myapp.MyApplication:na]
at liquibase.Scope.child(Scope.java:179) ~[org.myapp.MyApplication:na]
at liquibase.Scope.child(Scope.java:158) ~[org.myapp.MyApplication:na]
at liquibase.Liquibase.runInScope(Liquibase.java:2447) ~[na:na]
... 24 common frames omitted
Tested with the following framework & library versions:
Spring Boot: 3.0.4
org.graalvm.buildtools.native
: 0.9.20
liquibase-core
: 4.17.2
liquibase-sessionlock
: 1.6.2
Hi @blagerweij - based on this information I think it would be best if the PGLockService.supports method excludes CockroachDB as an option for session lock. This query will return a row if it's CRDB:
SELECT name, setting FROM pg_settings where name = 'crdb_version';
What do you think?
Thanks for this extension!
Perhaps more a question than a bug: is there a minimum version of liquibase it is compatible with?
I have no problem with:
Spring Boot 2.7.0
Liquibase 4.9.1
but when I added it to:
Spring Boot 1.5.15
Liquibase 3.5.2
Application run failed with exception:
2022-08-11 15:05:38.601 ERROR [document-service,,,] 7 --- [ main] o.s.boot.SpringApplication : Application run failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'liquibase' defined in class path resource [org/springframework/boot/autoconfigure/liquibase/LiquibaseAutoConfiguration$LiquibaseConfiguration.class]: Invocation of init method failed; nested exception is java.lang.NoClassDefFoundError: liquibase/Scope
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1778)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:593)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:307)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1105)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:867)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:549)
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:140)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:742)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:389)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:311)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1213)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1202)
at pl.com.euro.kl2.document.DocumentService.main(DocumentService.java:16)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:47)
at org.springframework.boot.loader.Launcher.launch(Launcher.java:86)
at org.springframework.boot.loader.Launcher.launch(Launcher.java:50)
at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:51)
Caused by: java.lang.NoClassDefFoundError: liquibase/Scope
at com.github.blagerweij.sessionlock.SessionLockService.getLog(SessionLockService.java:157)
at com.github.blagerweij.sessionlock.SessionLockService.acquireLock(SessionLockService.java:81)
at liquibase.lockservice.StandardLockService.waitForLock(StandardLockService.java:207)
at liquibase.Liquibase.update(Liquibase.java:184)
at liquibase.Liquibase.update(Liquibase.java:179)
at liquibase.integration.spring.SpringLiquibase.performUpdate(SpringLiquibase.java:353)
at liquibase.integration.spring.SpringLiquibase.afterPropertiesSet(SpringLiquibase.java:305)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1837)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1774)
... 26 common frames omitted
Caused by: java.lang.ClassNotFoundException: liquibase.Scope
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at org.springframework.boot.loader.LaunchedURLClassLoader.loadClass(LaunchedURLClassLoader.java:92)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
... 35 common frames omitted
I have also tried add system property liquibase.scan.packages, but result is the same.
I have a spring boot project (2.7.1) with liquibase (4.15.0) and sessionlock (1.5.3).
i use postgres in docker for my tests.
i have the following extra properties:
spring.jpa.hibernate.ddl-auto=none
spring.liquibase.drop-first=true
spring.liquibase.clear-checksums=true
The issue is that drop-first no longer works as expected because the table databasechangelog
does not get dropped, but all other tables are => whenever i start a new test suite no migrations are run as liquibase believes all is set up.
How to repro:
After the second run, all tests fail and only the table databasechangelog
remains.
After i remove sessionLock, everything works as expected.
Is it possible that sessionLock breaks something for drop-fist
/dropAll
?
Hi, I have some Kotlin services which use using Liquibase-based library (just some boilerplate) to perform the migration. I wanted to add liquibase-sessionlock to this library to introduce it to all my services with a simple library version bump.
Unfortunately, services are using standard liquibase lock.
I've tried to add com.github.blagerweij.sessionlock
to MANIFEST.MF of both service and library, but without any success.
When I added sessionlock directly to my service it started instantly.
I'm using liquibase-core:4.15.0 and liquibase-sessionlock:1.5.3.
Do you have any idea why it doesn't work?
We are running integration tests with spring.liquibase.drop-first=true
:
We observe that the 2nd+ integration tests ultimately time out and fail because Liquibase cannot acquire a lock.
Our theory after code review is the following:
liquibase.command.core.InternalDropAllCommandStep#run
calls liquibase.database.AbstractJdbcDatabase#dropDatabaseObjects
which calls com.github.blagerweij.sessionlock.SessionLockService#destroy
.com.github.blagerweij.sessionlock.SessionLockService#hasChangeLogLock
to false.com.github.blagerweij.sessionlock.SessionLockService#releaseLock()
(and destroy() and resetServices() in a finally clause but it has no effect because releaseLock()
just returns due to wrong hasChangeLogLock = false
state after destroy()
.com.github.blagerweij.sessionlock.SessionLockService#acquireLock()
is called, it fails to acquire a lock because it was never properly released in the DB.Maybe com.github.blagerweij.sessionlock.SessionLockService#reset
should just call com.github.blagerweij.sessionlock.SessionLockService#forceReleaseLock
instead?
Is there a reason the init override is empty?
This seems to result in the databasechangeloglock table not being created at application start-up and causes Liquibase to crash when initializing an empty database with initial schema, DDL, etc.
Link to line of code that overrides the init command in SessionLockService:
Copy of error message:
ERROR: relation "databasechangeloglock" does not exist [Failed SQL: (0) ALTER TABLE databasechangeloglock SET SCHEMA myschema]
This was ran as part of a changelog where I am changing the schema of the databasechangeloglock table that should be initialized to move it from public to the schema I am using.
To re-create this, I have 2 changelogs in yaml format and running liquibase at app start-up for a Spring Boot application:
databaseChangeLog:
- changeSet:
dbms: postgresql
id: 1678996872602-1
author: user (init schema)
changes:
- sql:
sql: CREATE SCHEMA IF NOT EXISTS myschema;
databaseChangeLog:
- changeSet:
dbms: postgresql
id: 1678996879842-1
author: user (init PG Liquibase)
changes:
- sql:
sql: ALTER TABLE databasechangelog SET SCHEMA myschema;
- sql:
sql: ALTER TABLE databasechangeloglock SET SCHEMA myschema;
Framework and versions:
spring: 2.7.6
liquibase-core: 4.19.0
liquibase-sessionlock:1.6.2
Hi @blagerweij,
I am running into an error with Liquibase where the generated user-level lock name is too long, resulting in this error:
Incorrect user-level lock name 'XXXXXXXXX........XXXXXXXXXX'
The lock name is based on the schema name and table name, which I do not have control over changing in this case.
Overriding the lock name calculation directly is difficult since the method that generates it is private.
Do you have any suggestions on the best way to resolve this error without changing the schema/table names themselves? I would appreciate any guidance you can provide.
Thank you!
I have several different Liquibase changelogs, with different different liquibaseSchemaName
from liquibase.properties
file.
Using plain Liquibase without this extension, it places the Liquibase tables, including changeloglock
in the schema specified in the property liquibaseSchemaName
.
When using the liquibase-sessionlock extension it creates the lock handle with database.getDefaultSchemaName()
which is the default schema for the connection.
Since we use one user for all migrations, we'd get a lot of unnecessary blocking of migrations.
My suggestion is to use database.getLiquibaseSchemaName()
in order to get a handle that mimics the default behavior of Liquibase.
I have a fork of this repo and is currently testing this change for Oracle.
Hi - your library looks good & solves a bit problem with Liquibase.
CockroachDB using Postgres database drive doesn't work. This isn't actually your fault, but Cockroach has implemented pg_advisory_lock(key bigint)
etc but not pg_advisory_lock(key1 int, key2 int)
(2 int version). I've submitted:
cockroachdb/cockroach#106575 for them to fix the issue.
At this stage let's wait for the Cockroach team to respond.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.