I am trying to run my spring neo4j backend application in a docker compose container, and another container for the neo4j database.
Both of them are working, but i cant get a connection from my application running in the docker container. As soon, im trying to connect to an endpoint i get this error message:
backend | 2020-10-11 13:20:06.784 INFO 1 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 22 ms
backend | 2020-10-11 13:20:06.952 INFO 1 --- [nio-8080-exec-1] Driver : Direct driver instance 1073288749 created for server address localhost:7687
backend | 2020-10-11 13:20:07.068 ERROR 1 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.transaction.CannotCreateTransactionException: Could not open Neo4j Session for transaction; nested exception is org.neo4j.ogm.exception.ConnectionException: Could not create driver instance] with root cause
Why does the error message seems like the application allways tries to connect the database on localhost:7678. How can i configure the address of the database?
If i run the backend application localy, and the db in a container, i can connect correctly to the database.
Are you using SDN 6? In this case the environment variable to set is SPRING_NEO4J_URI=bolt://neo4j:7687 as we changed this to align with the other database connection properties existing in Spring Boot starting with Spring Boot 2.4.
If you are using Spring Boot 2.3 or lower and Spring Data Neo4j 5.x:
Another problem that can occur is a race condition between both services.
The problem is not the configuration itself but the neo4j image that gets marked as up before the rest of the db boot up sequence (http, bolt server etc.) is finished.
This very moment the backend gets already started and if it is fast enough, it will try to reach the database before the ports are up.
Edit: I liked the problem so much, that I gathered more information about this. It seems that the behaviour is more general when it comes (not just) to databases. In this article a few tools are mentioned that can help you to have a better experience: Control startup and shutdown order in Compose | Docker Documentation
For me, the problem was actually in the race condition between the Spring-Backend and the Neo4j-Server, as @gerrit.meier suggested. Neo4j takes a few seconds to start and in the meantime the backend is already trying to connect, resulting in a ServiceUnavailableException.
So implementing a health check for Neo4j fixed the problem for me.
Here is my docker-compose.yml:
services:
# Service for spring boot backend
app:
image: ${IMAGE_DEV}
container_name: app
ports:
- "8080:8080"
depends_on:
neo4j-db:
condition: service_healthy # Wait for neo4j to be ready
links:
- neo4j-db
environment:
NEO4J_URI: bolt://neo4j-db:7687
NEO4J_PASSWORD: secret
# Service for Neo4j database
neo4j-db:
image: neo4j:4.1.4
container_name: app-neo4j-db
restart: on-failure
volumes:
- app-neo4j-db:/data
ports:
- "7474:7474" # HTTP
- "7687:7687" # Bolt
environment:
NEO4J_AUTH: neo4j/secret # Username: neo4j, Password: secret
dbms_connector_bolt_listen__address: neo4j-db:7687
dbms_connector_bolt_advertised__address: neo4j-db:7687
healthcheck:
test: cypher-shell --username neo4j --password secret 'MATCH (n) RETURN COUNT(n);' # Checks if neo4j server is up and running
interval: 10s
timeout: 10s
retries: 5
volumes:
app-neo4j-db: