tbroyer / gwt-maven-plugin

Starting fresh on building GWT projects with Maven
https://tbroyer.github.io/gwt-maven-plugin/
Apache License 2.0
169 stars 41 forks source link

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

Open zouabimourad opened 6 years ago

zouabimourad commented 6 years ago

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 commented 6 years ago

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

tbroyer commented 6 years ago

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

Patches welcome!

zouabimourad commented 6 years ago

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.

tbroyer commented 6 years ago

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)

zouabimourad commented 6 years ago

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 !

tbroyer commented 6 years ago

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)

jjYBdx4IL commented 5 years ago

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 commented 5 years ago

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 commented 5 years ago

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();
            }
        }));
tbroyer commented 5 years ago

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.

jjYBdx4IL commented 5 years ago

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 commented 5 years ago

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

jjYBdx4IL commented 5 years ago

the build failure is not because of my changes btw

tbroyer commented 2 years ago

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.

ratuka commented 2 years ago

You could also probably use gwt:dev

Do you mean gwt:devmode?

tbroyer commented 2 years ago

Oops, yes, gwt:devmode indeed.

ratuka commented 2 years ago

Oops, yes, gwt:devmode indeed.

and without -noserver

tbroyer commented 2 years ago

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

craigmit commented 9 months ago

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! 👍

FrankHossfeld commented 9 months ago

@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?

tbroyer commented 9 months ago

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.

FrankHossfeld commented 9 months ago

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.

craigmit commented 8 months ago

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.

tbroyer commented 8 months ago

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.

craigmit commented 8 months ago

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.

tbroyer commented 8 months ago

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.