mojohaus / exec-maven-plugin

Exec Maven Plugin
https://www.mojohaus.org/exec-maven-plugin/
Apache License 2.0
169 stars 98 forks source link

Maven exec plugin java goal with RMI exits early #436

Open oliviercailloux opened 3 months ago

oliviercailloux commented 3 months ago

The org.codehaus.mojo:exec-maven-plugin:3.3.0 plugin “java” goal documentation states that “daemon threads are joined and interrupted once all known non daemon threads have quit”. That is not what I observe with some code involving an RMI thread (except that I do not know what is an “unknown” thread). It looks like either a bug or a problem in the documentation.

Details

My “Server” program starts a non-daemon thread (through RMI) and when I run it using the “java” goal, the JVM exits when reaching the end of the main method. I’d expect that it keeps running due to the non daemon thread still running. When I run it using direct invocation of java, as expected, the program keeps running even after main finishes.

Code

Here is the Server.

public class Server {
  public static void main(String[] args) throws Exception {
    Registry registry = LocateRegistry.createRegistry(Registry.REGISTRY_PORT);
    RemoteTest engine = new RemoteTestImpl();
    RemoteTest stub = (RemoteTest) UnicastRemoteObject.exportObject(engine, 0);
    registry.rebind("RemoteTestJ2", stub);
    Thread.sleep(3000);
    Thread.getAllStackTraces().keySet().forEach(thread -> {
      System.out.println("Thread: " + thread.getName() + " is daemon: " + thread.isDaemon());
    });
  }
}

Here is the Client.

public class User {
  public static void main(String[] args) throws Exception {
    Registry registry = LocateRegistry.getRegistry(Registry.REGISTRY_PORT);
    RemoteTest rem = (RemoteTest) registry.lookup("RemoteTestJ2");
    while(true) {
      System.out.println("Tested: " + rem.test(0, 1));
    }
  }
}

The full code is here.

Reproduce the problem

Expected: The RMI mechanism starts a non-daemon thread in the background and prevents exit of the JVM, so that the Server stays alive indefinitely and the Client prints forever the result of the test call.

Actual: the Server starts, RMI starts a non-daemon thread as expected (as well as daemon threads), the Server sleeps for three seconds, prints its threads, and exits. The Client, meanwhile, starts flooding the terminal with results of the test calls, but after three seconds, crashes with a stack trace complaining that it cannot reach the remote end any more.

Variants with no problem

Both the exec plugin and the RMI aspect seem required to trigger this odd behavior.

If running the server with java -cp "target/classes/" io.github.oliviercailloux.javagrade.graders.Server instead of the exec plugin, the server keeps running as expected. Same if I use exec:java (with appropriate options).

Alternatively, if I change the server code to simply start a new Thread that is kept busy (sleeps in a while loop), the server keeps running as expected.

Also posted on SO.

slawekjaranowski commented 3 months ago

There is a response on SO ... should we fix some of documentation ...?

PR are welcome

oliviercailloux commented 3 months ago

I may have missed something but it seems to me that the response proposed on SO is a workaround. It does not tackle the discrepancy between the doc and the observed behavior of the exec goal.

oliviercailloux commented 2 months ago

To make it perhaps clearer: my bug report is about the java goal not quitting once all known non daemon threads have quit. The doc states that it should.