Documentation for Spring boot integration and potential bug
marcindz88 opened this issue · 7 comments
Hi,
I was trying to configure liquibase-neo4j to run on spring boot startup, but encountered weird behavior where it runs an endless loop to acquire a lock "unique_liquibase_lock" and no changesets are executed. I tried to change the changesets but it does not change the situation.
Could you add documentation on how to configure liquibase-neo4j with spring boot because maybe I am doing something wrong.
My configuration currently:
application.yaml:
spring:
datasource:
driver-class-name: liquibase.ext.neo4j.database.jdbc.Neo4jDriver
url: jdbc:neo4j:bolt://localhost:7687
username: neo4j
password: xxxxxxxxx
liquibase:
change-log: classpath:db/changelog/db.changelog-master.xml
pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.liquibase</groupId>
<artifactId>liquibase-core</artifactId>
</dependency>
<dependency>
<groupId>org.liquibase.ext</groupId>
<artifactId>liquibase-neo4j</artifactId>
</dependency>
</dependencies>
Spring boot version: 3.1.4
Liquibase-neo4j version 4.24.0
I get repeating logs like following:
2023-10-12T23:33:48.604+02:00 DEBUG 24056 --- [pool-4-thread-1] liquibase.executor : CREATE CONSTRAINT `unique_liquibase_lock` IF NOT EXISTS FOR (n:`__LiquibaseLock`) REQUIRE n.`lockedBy` IS UNIQUE
2023-10-12T23:33:48.611+02:00 DEBUG 24056 --- [pool-4-thread-1] liquibase.executor : 0 row(s) affected
After a while application crashes and logs are as follows:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'liquibase' defined in class path resource [org/springframework/boot/autoconfigure/liquibase/LiquibaseAutoConfiguration$LiquibaseConfiguration.class]: Could not acquire change log lock despite no lock currently stored
Caused by: liquibase.exception.LockException: Could not acquire change log lock despite no lock currently stored
at liquibase.ext.neo4j.lockservice.Neo4jLockService.waitForLock(Neo4jLockService.java:73) ~[liquibase-neo4j-4.24.0.jar:4.24.0]
at liquibase.Liquibase.lambda$update$1(Liquibase.java:243) ~[liquibase-core-4.20.0.jar:na]
at liquibase.Scope.lambda$child$0(Scope.java:187) ~[liquibase-core-4.20.0.jar:na]
at liquibase.Scope.child(Scope.java:196) ~[liquibase-core-4.20.0.jar:na]
at liquibase.Scope.child(Scope.java:186) ~[liquibase-core-4.20.0.jar:na]
at liquibase.Scope.child(Scope.java:165) ~[liquibase-core-4.20.0.jar:na]
at liquibase.Liquibase.runInScope(Liquibase.java:2639) ~[liquibase-core-4.20.0.jar:na]
at liquibase.Liquibase.update(Liquibase.java:236) ~[liquibase-core-4.20.0.jar:na]
at liquibase.Liquibase.update(Liquibase.java:221) ~[liquibase-core-4.20.0.jar:na]
at liquibase.integration.spring.SpringLiquibase.performUpdate(SpringLiquibase.java:329) ~[liquibase-core-4.20.0.jar:na]
at liquibase.integration.spring.SpringLiquibase.afterPropertiesSet(SpringLiquibase.java:284) ~[liquibase-core-4.20.0.jar:na]
Caused by: java.util.concurrent.ExecutionException: java.lang.RuntimeException: Cannot run more queries in this transaction, it has either experienced an fatal error or was explicitly terminated [Failed SQL: CREATE CONSTRAINT `unique_liquibase_lock` IF NOT EXISTS FOR (n:`__LiquibaseLock`) REQUIRE n.`lockedBy` IS UNIQUE]
at java.base/java.util.concurrent.FutureTask.report(FutureTask.java:122) ~[na:na]
at java.base/java.util.concurrent.FutureTask.get(FutureTask.java:205) ~[na:na]
Hello, @marcindz88, thanks for the report.
Let me try to reproduce the error.
@marcindz88 can you try https://github.com/fbiville/liquibase-neo4j-issue-479 and tweak it if necessary (please send a PR to that repo if that's the case)?
I could not reproduce the issue you are having, I'm probably missing a few details?
Side note: I highly recommend the use of spring.liquibase.driver-class-name
instead of spring.datasource.driver-class-name
if you can.
liquibase.ext.neo4j.database.jdbc.Neo4jDriver
is not a general-purpose JDBC implementation, but one tailored for Liquibase usage.
Hi, thanks a lot for a quick reply.
I found what the issue was...
I have set the version of liquibase-neo4j to 4.2.4, and did not set the version for liquibase (as it is inherited from spring default config 4.2.0). I could not find what was the difference between your reproduction repo and my code. The difference was that you named the version property for liquibase-neo4j and liquibase as liquibase.version
which overrided spring default version. I had a different name, and hence the versions were not compatible...
Anyway, thanks for the example, I was struggling to find one.
Could you tell me how can I set the configuration in spring.liquibase.driver-class-name
and not in spring.datasource as I am not using spring jdbc (I am using spring-boot-starter-data-neo4j) and it throws an exception as follows:
Description:
Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured.
Reason: Failed to determine a suitable driver class
Action:
Consider the following:
If you want an embedded database (H2, HSQL or Derby), please put it on the classpath.
If you have database settings to be loaded from a particular profile you may need to activate it (no profiles are currently active).
I have neo4j configuration in different location as I am using spring-data-neo4j:
spring:
neo4j:
uri: neo4j://localhost:7687
authentication:
username: neo4j
password: xxxxx
I would have to get another dependency for neo4j jdbc client to set it in spring.datasource, while I am using JDBC only for liquibase.
@marcindz88 unfortunately, there is a hard dependency in Spring Boot Liquibase autoconfiguration with the JDBC starter that I do not really understand.
Ideally, the JDBC starter would be removed entirely, but then Liquibase is not configured at all.
The autoconfiguration report explains why:
LiquibaseAutoConfiguration.LiquibaseConfiguration:
Did not match:
- @ConditionalOnClass did not find required class 'org.springframework.jdbc.core.ConnectionCallback' (OnClassCondition)
I think the only way around this is for liquibase-neo4j
to bring its own autoconfiguration class.
Ok, I think that there should be a way for setting up liquibase without jdbc starter, but for now I will stay with current configuration.
Thanks a lot for help.
@marcindz88 I agree with you.
I opened spring-projects/spring-boot#37936 but that won't be implemented just yet.
In the meantime, the extension (or a new downstream project) should provide a SpringLiquibase
bean that just works without JDBC starter/