gwt-maven-plugin icon indicating copy to clipboard operation
gwt-maven-plugin copied to clipboard

Code Server's Process Still Running After Stopping the maven launcher ( CTRL + C )

Open zouabimourad opened this issue 7 years ago • 26 comments

Hi,

When i launch mvn gwt:codesever 3 process are started ( maven jvm , cmd and codesever jvm )

When I Stop mvn .. the 2 first process are stopped but the codeserver jvm is still running

Regards.

zouabimourad avatar Apr 10 '18 13:04 zouabimourad

Same thing when i stop gwt compilation .. the leaf java process ( gwt compiler process ) is still running ...

zouabimourad avatar Apr 11 '18 22:04 zouabimourad

I've been a Linux user for years and I don't have any expertise on Windows idiosyncrasies.

Patches welcome!

tbroyer avatar May 16 '18 07:05 tbroyer

I have the same problem with the 1.8.2 version of the legacy plugin but the 1.8.1 is ok

I will try to fix it.

zouabimourad avatar May 16 '18 07:05 zouabimourad

It might be due to an update of the plexus-utils dependency (from 3.0.16 to 3.1.0 between org.codehaus.mojo:gwt-maven-plugin 2.8.1 and 2.8.2; and from 3.0.21 to 3.1.0 in net.ltgt.gwt.maven:gwt-maven-plugin 1.0-rc-9 compared to previous versions). You should be able to test with earlier versions of plexus-utils by declaring them in the plugin's dependencies:

<plugin>
  <groupId>net.ltgt.gwt.maven</groupId>
  <artifactId>gwt-maven-plugin</artifactId>
  <version>1.0-rc-9</version>
  <dependencies>
    <dependency>
      <groupId>org.codehaus.plexus</groupId>
      <artifactId>plexus-utils</artifactId>
      <version>3.0.16</version>
    </dependency>
  </dependencies>
</plugin>

If that fixes it for you, then we'd have at least a lead to explore and possibly report it to plexus-utils (if that doesn't fix it though, it might be that the dependency is not taken into account; run Maven with -X –debug logs– and look for the plugin's class world/realm to see what's actually used)

tbroyer avatar May 16 '18 14:05 tbroyer

It works fine with the dependency override. There is no a cmd process between maven's JVM and Codeserver's JVM anymore .. and after Exit all the JMVs are Stopped. Thx !

zouabimourad avatar May 16 '18 17:05 zouabimourad

Let's keep it open please. You have a workaround, but this still needs fixing (even if that only means waiting for a new version of plexus-utils with a fix and upgrading to it; or temporarily downgrading)

tbroyer avatar May 18 '18 10:05 tbroyer

Easiest solution would be to use jetty's stopPort if possible.

If that's not possible, a cross-platform library to kill processes by port number would be in order. (win10/linux: netstat, win10: tasklist+taskkill, linux; kill)

Here is a quick and dirty solution I used in one of my projects:

https://github.com/jjYBdx4IL/example-maven-project-setups/blob/master/gwt-example/devel-it/src/main/resources/startStop.sh

But it is mixed with Linux where I simply put an environment variable into the started process and then identify the process using that unique tag. That's not possible under Windows it seems.

However, I should note that GWT dev mode does not work too well under Windows anyways because it seems that it sometimes has a race condition where the strict file locking on Windows produces a file access conflict with itself.

Maybe it's possible to NOT FORK the codeserver and run it inside the main maven process, at least when using the @default-cli execution? Or attach the forked process' resources to the parent process such that a termination of the parent leads to the termination of the child somehow?

jjYBdx4IL avatar Jan 29 '19 21:01 jjYBdx4IL

Adding

  <plugin>
    <groupId>net.ltgt.gwt.maven</groupId>
    <artifactId>gwt-maven-plugin</artifactId>
    <configuration>
      <systemProperties>
        <STOP.PORT>9999</STOP.PORT>
        <STOP.KEY>GWTCODESERVER</STOP.KEY>
      </systemProperties>
    </configuration>
  </plugin>

allows to shut down a stray codeserver by sending the key to the stop port:

java -jar ./jetty-distribution-9.4.14.v20181114/start.jar -DSTOP.PORT=9999 -DSTOP.KEY=GWTCODEGSERVER--stop

So I recommend setting the stop port by default with a default key value and checking the port connectivity before trying to start the codeserver.

Also, on Windows the codeserver is likely to keep locking files in target/ when using CTRL-C. Not sure how to go about this. Probably, there should be a gwt:stop command that is tied to the pre-clean phase by default.

jjYBdx4IL avatar Jan 30 '19 23:01 jjYBdx4IL

https://bugs.java.com/bugdatabase/view_bug.do?bug_id=4717969

a shutdown hook would at least solve the CTRL-C issue on Windows:

        final ProcessBuilder pb =
            new ProcessBuilder("java", "ControlCProblemDemo");
            final Process p = pb.start();
        Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
            
            @Override
            public void run() {
                System.out.println("killing it");
                p.destroyForcibly();
            }
        }));

jjYBdx4IL avatar Jan 31 '19 00:01 jjYBdx4IL

There is such a shutdown hook already, with the exception that it calls destroy() rather than destroyForcibly() (plexus-utils is likely to have/want to support old JVMs though, and destroyForcibly()w as added in 1.8). https://github.com/codehaus-plexus/plexus-utils/blob/plexus-utils-3.1.1/src/main/java/org/codehaus/plexus/util/cli/CommandLineUtils.java#L134-L152 That being said, on Windows, destroyForcibly() just calls destroy(): https://github.com/unofficial-openjdk/openjdk/blob/2357b5fc925a96e53e6e9a84230be327424ad1ce/src/java.base/windows/classes/java/lang/ProcessImpl.java#L553-L557

IOW, what you're proposing is already there.

On Windows, a workaround might be to use gwt:devmode with <devmodeArg>-noserver</devmodeArg>; that way you can easily stop the code server by closing the devmode window.

tbroyer avatar Jan 31 '19 10:01 tbroyer

okay, I didn't see that the shutdown hook was already used because the forked plexus-utils repo has a non-working search function. pft.

Apart from that, I played around with plexus-utils to find out why my own test case works, but plexus-utils doesn't. Answer: it seems to be related to the stream pumpers. When I replace Runtime.exec() with ProcessBuilder and use its inheritIO() instead, the child process goes away as expected. Specifically using Redirect.INHERIT on the child's STDIN fixes the issue - maybe the child's STDIN FD doesn't get closed the way it's currently handled.

Commandline:

/**
 * Executes the command.
 */
public Process execute()
    throws CommandLineException
{
    // TODO: Provided only for backward compat. with <= 1.4
    verifyShellState();

    Process process;

    // addEnvironment( "MAVEN_TEST_ENVAR", "MAVEN_TEST_ENVAR_VALUE" );

    String[] environment = getEnvironmentVariables();

    File workingDir = shell.getWorkingDirectory();

    ProcessBuilder pb = new ProcessBuilder(getCommandline());
    pb.directory(workingDir);
    pb.inheritIO();
    if (environment != null) {
        for (String s : environment) {
            String[] kv = s.split("=", 2);
            pb.environment().put(kv[0], kv[1]);
        }
    }
    
    try
    {
        if ( workingDir != null ) {
            if ( !workingDir.exists() )
            {
                throw new CommandLineException( "Working directory \"" + workingDir.getPath()
                    + "\" does not exist!" );
            }
            else if ( !workingDir.isDirectory() )
            {
                throw new CommandLineException( "Path \"" + workingDir.getPath()
                    + "\" does not specify a directory." );
            }
        }

        process = pb.start();
    }
    catch ( IOException ex )
    {
        throw new CommandLineException( "Error while executing process.", ex );
    }

    return process;
}

jjYBdx4IL avatar Jan 31 '19 12:01 jjYBdx4IL

Patch: https://github.com/tbroyer/gwt-maven-plugin/pull/125

jjYBdx4IL avatar Feb 01 '19 10:02 jjYBdx4IL

the build failure is not because of my changes btw

jjYBdx4IL avatar Feb 08 '19 17:02 jjYBdx4IL

Update on this issue, because the workaround above no longer works as-is with version 1.0.1 (similar workarounds might work, downgrading both plexus-utils and plexus-io, possibly more dependencies): the bug is upstream in plexus-utils, which is used in many Maven plugins (including Surefire and the maven-compiler-plugin ‼), this is where it needs to be fixed.

I'll keep this issue open because indeed it's an issue with the plugin, but I'll only accept PRs that update plexus-utils to a version that fixes the bug.

In the mean time, don't use Ctrl+C or similar (killing the Maven task in Eclipse), and rather kill the GWT process itself directly. You could also probably use gwt:dev (with -noserver) instead of gwt:codeserver, as it will give you a Swing window that you can close to stop GWT.

tbroyer avatar Apr 26 '22 15:04 tbroyer

You could also probably use gwt:dev

Do you mean gwt:devmode?

ratuka avatar Oct 27 '22 19:10 ratuka

Oops, yes, gwt:devmode indeed.

tbroyer avatar Oct 27 '22 20:10 tbroyer

Oops, yes, gwt:devmode indeed.

and without -noserver

ratuka avatar Oct 27 '22 20:10 ratuka

with noserver: devmode is then equivalent to codeserver, just with an additional swing window.

tbroyer avatar Oct 27 '22 20:10 tbroyer

So, if you've created a client/server/shared architect, then instead of mvn gwt:codeserver -pl *-client -am, you'd do:

mvn gwt:devmode -pl *-client -am -Dnoserver

Works great, thanks! 👍

craigmit avatar Jan 29 '24 10:01 craigmit

@tbroyer in case GWT remove the DevMode (as mentioned here: (https://www.gwtproject.org/release-notes.html#Release_Notes_2_11_0), will this have an impact on the work around?

FrankHossfeld avatar Jan 29 '24 11:01 FrankHossfeld

For the time being, the goal seems to be to eventually default to -noserver (https://github.com/gwtproject/gwt/issues/9863) (and then maybe remove the JettyLauncher in favor of the newly added StaticResourcesServer, that's at least what I would do if you ask me), but not to remove DevMode entirely.

tbroyer avatar Jan 29 '24 11:01 tbroyer

Yes, that makes sense. So, the workaround will also work in the future. I was unsure, if it might fail in the future and a new workaround is needed. Thanks.

FrankHossfeld avatar Jan 29 '24 11:01 FrankHossfeld

So, if you've created a client/server/shared architect, then instead of mvn gwt:codeserver -pl *-client -am, you'd do:

mvn gwt:devmode -pl *-client -am -Dnoserver

Works great, thanks! 👍

Note: After a mvn clean the devmode solution will break. The browser won't be able to find the nocache.js file.

Running the mvn gwt:codeserver -pl *-client -am once (and then manually killing it), the devmode solution will start working again. I'm not entirely sure why, I suspect it's something to do with the target/gwt/codeserver directory it creates.

craigmit avatar Feb 10 '24 09:02 craigmit

Did you configure warDir to the same value as codeserver's launcherDir? If not, then devmode won't generate the nocache.js where you expect them, that's why you'd need to run codeserver to generate them first.

tbroyer avatar Feb 10 '24 10:02 tbroyer

Ah, thank you @tbroyer . Yes, that was the issue. Now with:

<plugin>
	<groupId>net.ltgt.gwt.maven</groupId>
	<artifactId>gwt-maven-plugin</artifactId>
	<inherited>false</inherited>
	<configuration>
		<launcherDir>${basedir}/mywebapp-server/target/classes/launcherDir/</launcherDir>
		<warDir>${basedir}/mywebapp-server/target/classes/launcherDir/</warDir>
	</configuration>
</plugin>

And now it still works great after a mvn clean.

craigmit avatar Feb 10 '24 11:02 craigmit

Fwiw, I just published version 2024.2.11 of the gwt-maven-archetypes that adds the warDir configuration, and a note in the README explaining when one may want to use devmode, and linking here. It also adds the -noserver argument.

tbroyer avatar Feb 11 '24 19:02 tbroyer