Javadoc states:

Stops the web server. Calling this method on an already stopped server has no effect.

I reviewed all WebServer implementations and identified some inconsistencies among them.

In the case of TomcatWebServer, it consistently tries to removeServiceConnectors, and stop method can be invoked multiple times.


public void stop() throws WebServerException {
    synchronized (this.monitor) {
        boolean wasStarted = this.started;
        try {
            this.started = false;
            if (this.gracefulShutdown != null) {
                this.gracefulShutdown.abort();
            }
            removeServiceConnectors();
        }
        catch (Exception ex) {
            throw new WebServerException("Unable to stop embedded Tomcat", ex);
        }
        finally {
            if (wasStarted) {
                containerCounter.decrementAndGet();
            }
        }
    }
}

For NettyWebServer, if an error occurs, it silently catches the exception without throwing a WebServerException. Additionally, subsequent calls to stop() will have no effect.

    public void stop() throws WebServerException {
    if (this.disposableServer != null) {
        if (this.gracefulShutdown != null) {
            this.gracefulShutdown.abort();
        }
        try {
            if (this.lifecycleTimeout != null) {
                this.disposableServer.disposeNow(this.lifecycleTimeout);
            }
            else {
                this.disposableServer.disposeNow();
            }
        }
        catch (IllegalStateException ex) {
            // Continue
        }
        this.disposableServer = null;
    }
}

Similarly to Tomcat, JettyWebServer attempts to stop its connectors and allows the stop method to be invoked multiple times.

public void stop() {
    synchronized (this.monitor) {
        this.started = false;
        if (this.gracefulShutdown != null) {
            this.gracefulShutdown.abort();
        }
        try {
            for (Connector connector : this.server.getConnectors()) {
                connector.stop();
            }
        }
        catch (InterruptedException ex) {
            Thread.currentThread().interrupt();
        }
        catch (Exception ex) {
            throw new WebServerException("Unable to stop embedded Jetty server", ex);
        }
    }
}

In contrast, UndertowWebServer makes the second call to stop() ineffective, preventing any retries to stop the WebServer in case of failure.


@Override
public void stop() throws WebServerException {
    synchronized (this.monitor) {
        if (!this.started) {
            return;
        }
        this.started = false;
        if (this.gracefulShutdown != null) {
            notifyGracefulCallback(false);
        }
        try {
            this.undertow.stop();
            for (Closeable closeable : this.closeables) {
                closeable.close();
            }
        }
        catch (Exception ex) {
            throw new WebServerException("Unable to stop Undertow", ex);
        }
    }
}

Comment From: JayakrishnanJS

@nosan could u pls assign this issue to me

Comment From: wilkinsona

Thanks for the offer, @JayakrishnanJS, but this will have to be discussed by the core team to decide what, if anything, we want to do.