Skip to content

Allow Jetty's threadpool to be configured via properties #17871

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
* @author Andrew McGhie
* @author Rafiullah Hamedy
* @author Dirk Deyne
* @author HaiTao Zhang
* @since 1.0.0
*/
@ConfigurationProperties(prefix = "server", ignoreUnknownFields = true)
Expand Down Expand Up @@ -905,6 +906,21 @@ public static class Jetty {
*/
private Integer selectors = -1;

/**
* Maximum amount of threads.
*/
private Integer maxThreads = 200;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would not be better to set the maximum number of threads based on the number of available cores?

Copy link
Member

@snicoll snicoll Aug 15, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The values here are the default of the embedded servers and we don't deviate from that unless necessary. If you want to pursue this idea, I'd raise an issue against the Jetty project.


/**
* Minimum amount of threads.
*/
private Integer minThreads = 8;

/**
* Maximum thread idle time.
*/
private Integer idleTimeout = 60000;

public Accesslog getAccesslog() {
return this.accesslog;
}
Expand Down Expand Up @@ -933,6 +949,30 @@ public void setSelectors(Integer selectors) {
this.selectors = selectors;
}

public void setMinThreads(Integer minThreads) {
this.minThreads = minThreads;
}

public Integer getMinThreads() {
return this.minThreads;
}

public void setMaxThreads(Integer maxThreads) {
this.maxThreads = maxThreads;
}

public Integer getMaxThreads() {
return this.maxThreads;
}

public void setIdleTimeout(Integer idleTimeout) {
this.idleTimeout = idleTimeout;
}

public Integer getIdleTimeout() {
return this.idleTimeout;
}

/**
* Jetty access log properties.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.server.handler.HandlerCollection;
import org.eclipse.jetty.server.handler.HandlerWrapper;
import org.eclipse.jetty.util.thread.QueuedThreadPool;
import org.eclipse.jetty.util.thread.ThreadPool;

import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.cloud.CloudPlatform;
Expand All @@ -46,6 +48,7 @@
*
* @author Brian Clozel
* @author Phillip Webb
* @author HaiTao Zhang
* @since 2.0.0
*/
public class JettyWebServerFactoryCustomizer
Expand Down Expand Up @@ -78,6 +81,12 @@ public void customize(ConfigurableJettyWebServerFactory factory) {
.addServerCustomizers(new MaxHttpHeaderSizeCustomizer(maxHttpHeaderSize)));
propertyMapper.from(jettyProperties::getMaxHttpPostSize).asInt(DataSize::toBytes).when(this::isPositive)
.to((maxHttpPostSize) -> customizeMaxHttpPostSize(factory, maxHttpPostSize));
propertyMapper.from(jettyProperties::getMaxThreads).when(this::isPositive)
.to((maxThreads) -> customizeMaxThreads(factory, maxThreads));
propertyMapper.from(jettyProperties::getMinThreads).when(this::isPositive)
.to((minThreads) -> customizeMinThreads(factory, minThreads));
propertyMapper.from(jettyProperties::getIdleTimeout).when(this::isPositive)
.to((idleTimeout) -> customizeIdleTimeout(factory, idleTimeout));
propertyMapper.from(properties::getConnectionTimeout).whenNonNull()
.to((connectionTimeout) -> customizeConnectionTimeout(factory, connectionTimeout));
propertyMapper.from(jettyProperties::getAccesslog).when(ServerProperties.Jetty.Accesslog::isEnabled)
Expand Down Expand Up @@ -131,6 +140,33 @@ else if (handler instanceof HandlerCollection) {
});
}

private void customizeMaxThreads(ConfigurableJettyWebServerFactory factory, int maxThreads) {
factory.addServerCustomizers((connector) -> {
ThreadPool threadPool = connector.getThreadPool();
if (threadPool instanceof QueuedThreadPool) {
((QueuedThreadPool) threadPool).setMaxThreads(maxThreads);
}
});
}

private void customizeMinThreads(ConfigurableJettyWebServerFactory factory, int minThreads) {
factory.addServerCustomizers((connector) -> {
ThreadPool threadPool = connector.getThreadPool();
if (threadPool instanceof QueuedThreadPool) {
((QueuedThreadPool) threadPool).setMinThreads(minThreads);
}
});
}

private void customizeIdleTimeout(ConfigurableJettyWebServerFactory factory, int idleTimeout) {
factory.addServerCustomizers((connector) -> {
ThreadPool threadPool = connector.getThreadPool();
if (threadPool instanceof QueuedThreadPool) {
((QueuedThreadPool) threadPool).setIdleTimeout(idleTimeout);
}
});
}

private void customizeAccessLog(ConfigurableJettyWebServerFactory factory,
ServerProperties.Jetty.Accesslog properties) {
factory.addServerCustomizers((server) -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
* @author Quinten De Swaef
* @author Venil Noronha
* @author Andrew McGhie
* @author HaiTao Zhang
*/
class ServerPropertiesTests {

Expand Down Expand Up @@ -218,6 +219,24 @@ void testCustomizeJettySelectors() {
assertThat(this.properties.getJetty().getSelectors()).isEqualTo(10);
}

@Test
void testCustomizeJettyMaxThreads() {
bind("server.jetty.max-threads", "10");
assertThat(this.properties.getJetty().getMaxThreads()).isEqualTo(10);
}

@Test
void testCustomizeJettyMinThreads() {
bind("server.jetty.min-threads", "10");
assertThat(this.properties.getJetty().getMinThreads()).isEqualTo(10);
}

@Test
void testCustomizeJettyIdleTimeout() {
bind("server.jetty.idle-timeout", "10");
assertThat(this.properties.getJetty().getIdleTimeout()).isEqualTo(10);
}

@Test
void testCustomizeUndertowServerOption() {
bind("server.undertow.options.server.ALWAYS_SET_KEEP_ALIVE", "true");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
import org.eclipse.jetty.server.HttpConfiguration.ConnectionFactory;
import org.eclipse.jetty.server.RequestLog;
import org.eclipse.jetty.server.RequestLogWriter;
import org.eclipse.jetty.util.thread.QueuedThreadPool;
import org.eclipse.jetty.util.thread.ThreadPool;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

Expand All @@ -49,6 +51,7 @@
*
* @author Brian Clozel
* @author Phillip Webb
* @author HaiTao Zhang
*/
class JettyWebServerFactoryCustomizerTests {

Expand Down Expand Up @@ -112,6 +115,36 @@ void accessLogCanBeEnabled() {
assertThat(logWriter.isAppend()).isFalse();
}

@Test
void maxThreadsCanBeCustomized() throws IOException {
bind("server.jetty.max-threads=100");
JettyWebServer server = customizeAndGetServer();
ThreadPool threadPool = server.getServer().getThreadPool();
if (threadPool instanceof QueuedThreadPool) {
assertThat(((QueuedThreadPool) threadPool).getMaxThreads()).isEqualTo(100);
}
}

@Test
void minThreadsCanBeCustomized() throws IOException {
bind("server.jetty.min-threads=100");
JettyWebServer server = customizeAndGetServer();
ThreadPool threadPool = server.getServer().getThreadPool();
if (threadPool instanceof QueuedThreadPool) {
assertThat(((QueuedThreadPool) threadPool).getMinThreads()).isEqualTo(100);
}
}

@Test
void idleTimeoutCanBeCustomized() throws IOException {
bind("server.jetty.idle-timeout=100");
JettyWebServer server = customizeAndGetServer();
ThreadPool threadPool = server.getServer().getThreadPool();
if (threadPool instanceof QueuedThreadPool) {
assertThat(((QueuedThreadPool) threadPool).getIdleTimeout()).isEqualTo(100);
}
}

private CustomRequestLog getRequestLog(JettyWebServer server) {
RequestLog requestLog = server.getServer().getRequestLog();
assertThat(requestLog).isInstanceOf(CustomRequestLog.class);
Expand Down