neo4j / neo4j-jdbc

Official Neo4j JDBC Driver
http://neo4j.github.io/neo4j-jdbc/
Apache License 2.0
131 stars 53 forks source link

Neo4J Driver is never closed, leaving the event loop threads running #405

Closed rjbaucells closed 1 year ago

rjbaucells commented 1 year ago

Creating a single JDBC connection with the neo4j jdbc driver leaves the neo4j-java-driver Driver event loop running...

public static void main(String[] args) throws SQLException {
    // connection properties
    var properties = new Properties();
    // credentials
    properties.put("user", "neo4j");
    properties.put("password", "password");
    // url
    var url = "jdbc:neo4j:bolt://my-neo4j-server:7687?database=neo4j";
    // create connection - checkpoint #1
    try (var connection = DriverManager.getConnection(url, properties)) {
        // do noting - checkpoint #2
        assert connection != null;
    }
    // checkpoint #3
}

Threads at checkpoint #1

image

Threads at checkpoint #2, the Driver event loop threads are running...

image

Threads at checkpoint #3, the Driver event loop threads continue running...

image

JDBC driver version:

<dependency>
    <groupId>org.neo4j</groupId>
    <artifactId>neo4j-jdbc-bolt</artifactId>
    <version>5.0.0</version>
</dependency>

Running the application with maven exec plugin reports threads are not stopped at program exit:

mvn exec:java -Dexec.mainClass="example.Application"

[INFO] Scanning for projects...
[INFO] 
[INFO] -------------< modules:test-jdbc >--------------
[INFO] Building Test JDBC 1.0.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO] 
[INFO] --- exec-maven-plugin:3.1.0:java (default-cli) @ test-jdbc ---
[WARNING] thread Thread[Neo4jDriverIO-2-1,10,example.Application] was interrupted but is still alive after waiting at least 14999msecs
[WARNING] thread Thread[Neo4jDriverIO-2-1,10,example.Application] will linger despite being asked to die via interruption
[WARNING] thread Thread[Neo4jDriverIO-2-2,10,example.Application] will linger despite being asked to die via interruption
[WARNING] thread Thread[Neo4jDriverIO-2-3,10,example.Application] will linger despite being asked to die via interruption
[WARNING] NOTE: 3 thread(s) did not finish despite being asked to via interruption. This is not a problem with exec:java, it is a problem with the running code. Although not serious, it should be remedied.
[WARNING] Couldn't destroy threadgroup org.codehaus.mojo.exec.ExecJavaMojo$IsolatedThreadGroup[name=example.Application,maxpri=10]
java.lang.IllegalThreadStateException
    at java.lang.ThreadGroup.destroy (ThreadGroup.java:803)
    at org.codehaus.mojo.exec.ExecJavaMojo.execute (ExecJavaMojo.java:319)
    at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo (DefaultBuildPluginManager.java:137)
    at org.apache.maven.lifecycle.internal.MojoExecutor.doExecute2 (MojoExecutor.java:370)
    at org.apache.maven.lifecycle.internal.MojoExecutor.doExecute (MojoExecutor.java:351)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:215)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:171)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:163)
    at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject (LifecycleModuleBuilder.java:117)
    at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject (LifecycleModuleBuilder.java:81)
    at org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder.build (SingleThreadedBuilder.java:56)
    at org.apache.maven.lifecycle.internal.LifecycleStarter.execute (LifecycleStarter.java:128)
    at org.apache.maven.DefaultMaven.doExecute (DefaultMaven.java:298)
    at org.apache.maven.DefaultMaven.doExecute (DefaultMaven.java:192)
    at org.apache.maven.DefaultMaven.execute (DefaultMaven.java:105)
    at org.apache.maven.cli.MavenCli.execute (MavenCli.java:960)
    at org.apache.maven.cli.MavenCli.doMain (MavenCli.java:293)
    at org.apache.maven.cli.MavenCli.main (MavenCli.java:196)
    at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0 (Native Method)
    at jdk.internal.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.java:77)
    at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke (Method.java:568)
    at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced (Launcher.java:282)
    at org.codehaus.plexus.classworlds.launcher.Launcher.launch (Launcher.java:225)
    at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode (Launcher.java:406)
    at org.codehaus.plexus.classworlds.launcher.Launcher.main (Launcher.java:347)
fbiville commented 1 year ago

Thanks for the report, we'll have a look ASAP.

conker84 commented 1 year ago

@rjbaucells thank you so much for opening the issue! The JDBC Driver is designed that way because creating a Driver instance is an expensive operation, so we make the Driver once and then rely on Sessions. Unfortunately, this is the best compromise otherwise using one Driver instance per Connection would kill the performance.

rjbaucells commented 1 year ago

@conker84 I agree with the design, creating a Driver instance per connection is a very expensive operation.

But, there should be a way to let the JDBC driver / Neo4J Java driver know that the application is exiting and the event loop must be terminated.

My specific use case is a process that will execute Liquibase statements against a database, and exit on completion. This process is going to be executed from a build pipeline and because of the process not existing clean, the pipeline is failing. I cannot ignore the failure since a "real" error in the execution must be handled.

An application that is creating the Neo4J Java Driver is in full control and can terminate the event loop (by closing the driver) at program exit. Using the JDBC driver is not possible. That is why I believe it is a BUG in the JDBC driver!

fbiville commented 1 year ago

@rjbaucells apologies for the delay, but have you checked the recent version of Liquibase? This uses a simplified, built-in JDBC driver which does not suffer from this issue.

rjbaucells commented 1 year ago

@fbiville Yes, I have tried the new version of Neo4J Liquibase plugin (4.19.X). Having a different problem with this version of Liquibase, so we are using 4.18 until the other issue is solved. We are manually killing the process for now...

fbiville commented 1 year ago

@fbiville Yes, I have tried the new version of Neo4J Liquibase plugin (4.19.X). Having a different problem with this version of Liquibase, so we are using 4.18 until the other issue is solved. We are manually killing the process for now...

If you have not opened an issue against Liquibase, please do, I will look into it!