Run Spring Neo4j in a docker container, but can't get connection to database

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

And this is my compose yaml

version: '3.7'

services:
    backend:
        build:
            context: .
            target: builded
        container_name: backend
        environment:
            - ORG_NEO4J_DRIVER_URI=bolt://neo4j:7687
        ports:
            - 8080:8080
        command: sh -c "java -Djava.security.egd=file:/dev/./urandom -jar /app/target/${APPLICATION_NAME}-${APPLICATION_VERSION}.jar"
        depends_on:
            - neo4j

    neo4j:
        image: neo4j:4.1.3
        container_name: neo4j
        volumes:
            - /opt/neo4j/data/conf:/conf
            - /opt/neo4j/data/data:/data
            - /opt/neo4j/data/import:/import
            - /opt/neo4j/data/logs:/logsneo4j
        environment:
            NEO4J_AUTH: neo4j/password
        ports:
            - 7687:7687 #Bolt
            - 7474:7474 #HTTP

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.

I hope anyone can help me. Thank you

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

Edit2: Since my colleagues reminded me of the things I also advocate all the time: there will be network failures! I add another option for you to handle this more nicely: Wait for the database to be available from your application on startup. https://github.com/spring-projects-experimental/spring-graalvm-native/blob/master/spring-graalvm-native-samples/data-neo4j/src/main/java/com/example/data/neo4j/CLR.java#L177

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:

And my application.properties:

spring.neo4j.uri=${NEO4J_URI}
spring.neo4j.authentication.username=neo4j
spring.neo4j.authentication.password=${NEO4J_PASSWORD}