spring-projects / spring-projects/spring-boot
Make stop behavior across various Web Server implementations consistent
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 81.5k
- Forks
- 42.7k
- Avg merge
- 2d 4h
- Merged PRs (30d)
- 65
Description
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);
}
}
}
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by comparing the stop implementations in TomcatWebServer, NettyWebServer, JettyWebServer, and UndertowWebServer, focusing on repeated calls and exception handling. Use the WebServer Javadoc as the behavioral baseline; done means the implementations consistently honor its idempotent stop contract while preserving failures that need to be reported.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java
- Domain
- backend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 32/100