diff --git a/hercules-elastic-adapter/README.md b/hercules-elastic-adapter/README.md index 7e5a06ee..8a212ebd 100644 --- a/hercules-elastic-adapter/README.md +++ b/hercules-elastic-adapter/README.md @@ -131,6 +131,18 @@ HTTP Server binds on host:port are defined in Main Application settings. `http.server.connection.threshold` - maximum active http connections, default value: `100000` +`http.server.readTimeout` - Configure a read timeout for a socket, in milliseconds. + +`http.server.writeTimeout` - Configure a write timeout for a socket, in milliseconds. + +`http.server.requestParseTimeout` - The maximum allowed time of reading HTTP request in milliseconds. +`-1` or missing value disables this functionality. + +`http.server.idleTimeout` - The idle timeout in milliseconds after which the channel will be closed. +If the underlying channel already has a read or write timeout set the smaller of the two values will be used for read/write timeouts. + +`http.server.noRequestTimeout` - The amount of time the connection can be idle with no current requests before it is closed. + ### Graphite metrics reporter settings `metrics.graphite.server.addr` - hostname of graphite instance to which metrics are sent, default value: `localhost` diff --git a/hercules-gate/README.md b/hercules-gate/README.md index e6bc5100..6341f2a1 100644 --- a/hercules-gate/README.md +++ b/hercules-gate/README.md @@ -205,6 +205,18 @@ HTTP Server binds on `:` are defined in Main Application settings. `http.server.throttling.requestTimeout` - timeout for request, which capacity throttling more then permissible, default value: `5000` +`http.server.readTimeout` - Configure a read timeout for a socket, in milliseconds. + +`http.server.writeTimeout` - Configure a write timeout for a socket, in milliseconds. + +`http.server.requestParseTimeout` - The maximum allowed time of reading HTTP request in milliseconds. +`-1` or missing value disables this functionality. + +`http.server.idleTimeout` - The idle timeout in milliseconds after which the channel will be closed. +If the underlying channel already has a read or write timeout set the smaller of the two values will be used for read/write timeouts. + +`http.server.noRequestTimeout` - The amount of time the connection can be idle with no current requests before it is closed. + ### Validation settings `validation.max.event.size` - max size of Hercules event, value must be consistent with broker setting `max.message.bytes`, default value: `500000` diff --git a/hercules-http/src/main/java/ru/kontur/vostok/hercules/http/HttpServer.java b/hercules-http/src/main/java/ru/kontur/vostok/hercules/http/HttpServer.java index 00334bf4..ca794650 100644 --- a/hercules-http/src/main/java/ru/kontur/vostok/hercules/http/HttpServer.java +++ b/hercules-http/src/main/java/ru/kontur/vostok/hercules/http/HttpServer.java @@ -16,6 +16,7 @@ * @author Gregory Koshelev */ public abstract class HttpServer implements Lifecycle { + private final AtomicReference state = new AtomicReference<>(HttpServerState.INIT); protected final String host; @@ -66,35 +67,46 @@ protected boolean stopInternal(long timeout, TimeUnit unit) { } public static final class Props { - public static final Parameter MAX_CONTENT_LENGTH = - Parameter.longParameter("maxContentLength"). - withDefault(HttpServerDefaults.DEFAULT_MAX_CONTENT_LENGTH). - withValidator(LongValidators.positive()). - build(); - - public static final Parameter CONNECTION_THRESHOLD = - Parameter.integerParameter("connection.threshold"). - withDefault(HttpServerDefaults.DEFAULT_CONNECTION_THRESHOLD). - withValidator(IntegerValidators.positive()). - build(); - - public static final Parameter IO_THREADS = - Parameter.integerParameter("ioThreads"). - withValidator(IntegerValidators.positive()). - build(); - - public static final Parameter WORKER_THREADS = - Parameter.integerParameter("workerThreads"). - withValidator(IntegerValidators.positive()). - build(); - - public static final Parameter ROOT_PATH = - Parameter.stringParameter("rootPath"). - withDefault("/"). - withValidator(Validators.and( - Validators.notNull(), - x -> x.startsWith("/") ? ValidationResult.ok() : ValidationResult.error("Should start with '/'"))). - build(); + + /** + * Maximum value of content length of HTTP-requests. + */ + public static final Parameter MAX_CONTENT_LENGTH = Parameter.longParameter("maxContentLength") + .withDefault(HttpServerDefaults.DEFAULT_MAX_CONTENT_LENGTH) + .withValidator(LongValidators.positive()) + .build(); + + /** + * Maximum simultaneous connections count. + */ + public static final Parameter CONNECTION_THRESHOLD = Parameter.integerParameter("connection.threshold") + .withDefault(HttpServerDefaults.DEFAULT_CONNECTION_THRESHOLD) + .withValidator(IntegerValidators.positive()) + .build(); + + /** + * Count of IO threads. + */ + public static final Parameter IO_THREADS = Parameter.integerParameter("ioThreads") + .withValidator(IntegerValidators.positive()) + .build(); + + /** + * Count of worker threads. + */ + public static final Parameter WORKER_THREADS = Parameter.integerParameter("workerThreads") + .withValidator(IntegerValidators.positive()) + .build(); + + /** + * Root path of HTTP-server. + */ + public static final Parameter ROOT_PATH = Parameter.stringParameter("rootPath") + .withDefault("/") + .withValidator(Validators.and( + Validators.notNull(), + x -> x.startsWith("/") ? ValidationResult.ok() : ValidationResult.error("Should start with '/'"))) + .build(); private Props() { /* static class */ diff --git a/hercules-management-api/README.md b/hercules-management-api/README.md index 19fd3970..18f13a9f 100644 --- a/hercules-management-api/README.md +++ b/hercules-management-api/README.md @@ -871,6 +871,18 @@ See Curator Config from Apache Curator documentation. Main settings are presente `http.server.rootPath` - base url, default value: `/` +`http.server.readTimeout` - Configure a read timeout for a socket, in milliseconds. + +`http.server.writeTimeout` - Configure a write timeout for a socket, in milliseconds. + +`http.server.requestParseTimeout` - The maximum allowed time of reading HTTP request in milliseconds. +`-1` or missing value disables this functionality. + +`http.server.idleTimeout` - The idle timeout in milliseconds after which the channel will be closed. +If the underlying channel already has a read or write timeout set the smaller of the two values will be used for read/write timeouts. + +`http.server.noRequestTimeout` - The amount of time the connection can be idle with no current requests before it is closed. + ### Management API settings `keys` - master API keys. diff --git a/hercules-stream-api/README.md b/hercules-stream-api/README.md index 7df2a6b5..2e100b35 100644 --- a/hercules-stream-api/README.md +++ b/hercules-stream-api/README.md @@ -224,6 +224,18 @@ See Apache Curator Config from Apache Curator documentation. Main settings are p `http.server.rootPath` - base url, default value: `/` +`http.server.readTimeout` - Configure a read timeout for a socket, in milliseconds. + +`http.server.writeTimeout` - Configure a write timeout for a socket, in milliseconds. + +`http.server.requestParseTimeout` - The maximum allowed time of reading HTTP request in milliseconds. +`-1` or missing value disables this functionality. + +`http.server.idleTimeout` - The idle timeout in milliseconds after which the channel will be closed. +If the underlying channel already has a read or write timeout set the smaller of the two values will be used for read/write timeouts. + +`http.server.noRequestTimeout` - The amount of time the connection can be idle with no current requests before it is closed. + ### Stream API settings `stream.api.pool.size` - consumers pool size. Default value: `4`. diff --git a/hercules-tracing-api/README.md b/hercules-tracing-api/README.md index 914bb890..b85f6048 100644 --- a/hercules-tracing-api/README.md +++ b/hercules-tracing-api/README.md @@ -199,6 +199,18 @@ default value: `localhost:8123` `http.server.rootPath` - base url, default value: `/` +`http.server.readTimeout` - Configure a read timeout for a socket, in milliseconds. + +`http.server.writeTimeout` - Configure a write timeout for a socket, in milliseconds. + +`http.server.requestParseTimeout` - The maximum allowed time of reading HTTP request in milliseconds. +`-1` or missing value disables this functionality. + +`http.server.idleTimeout` - The idle timeout in milliseconds after which the channel will be closed. +If the underlying channel already has a read or write timeout set the smaller of the two values will be used for read/write timeouts. + +`http.server.noRequestTimeout` - The amount of time the connection can be idle with no current requests before it is closed. + ## Command line `java $JAVA_OPTS -jar hercules-sentry-sink.jar application.properties=file://path/to/properties/file` diff --git a/hercules-undertow-util/src/main/java/ru/kontur/vostok/hercules/undertow/util/UndertowHttpServer.java b/hercules-undertow-util/src/main/java/ru/kontur/vostok/hercules/undertow/util/UndertowHttpServer.java index ec969afc..324a2b9f 100644 --- a/hercules-undertow-util/src/main/java/ru/kontur/vostok/hercules/undertow/util/UndertowHttpServer.java +++ b/hercules-undertow-util/src/main/java/ru/kontur/vostok/hercules/undertow/util/UndertowHttpServer.java @@ -1,6 +1,7 @@ package ru.kontur.vostok.hercules.undertow.util; import io.undertow.Undertow; +import io.undertow.UndertowOptions; import io.undertow.server.HttpServerExchange; import org.xnio.Options; import ru.kontur.vostok.hercules.http.HttpServer; @@ -17,6 +18,7 @@ * @author Gregory Koshelev */ public class UndertowHttpServer extends HttpServer { + private Undertow undertow; public UndertowHttpServer(String host, int port, Properties properties, HttpHandler handler) { @@ -26,23 +28,28 @@ public UndertowHttpServer(String host, int port, Properties properties, HttpHand @Override protected void startInternal() { int connectionThreshold = PropertiesUtil.get(Props.CONNECTION_THRESHOLD, properties).get(); - Parameter.ParameterValue ioThreads = PropertiesUtil.get(Props.IO_THREADS, properties); - Parameter.ParameterValue workerThreads = PropertiesUtil.get(Props.WORKER_THREADS, properties); - final ExceptionHandler exceptionHandler = new ExceptionHandler(handler); - Undertow.Builder builder = Undertow.builder(). - addHttpListener(port, host). - setHandler(exchange -> exceptionHandler.handle(wrap(exchange))). - setSocketOption(Options.CONNECTION_HIGH_WATER, connectionThreshold). - setSocketOption(Options.CONNECTION_LOW_WATER, connectionThreshold); + Undertow.Builder builder = Undertow.builder() + .addHttpListener(port, host) + .setHandler(exchange -> exceptionHandler.handle(wrap(exchange))) + .setSocketOption(Options.CONNECTION_HIGH_WATER, connectionThreshold) + .setSocketOption(Options.CONNECTION_LOW_WATER, connectionThreshold); - if (!ioThreads.isEmpty()) { - builder.setIoThreads(ioThreads.get()); - } - if (!workerThreads.isEmpty()) { - builder.setWorkerThreads(workerThreads.get()); - } + PropertiesUtil.get(Props.IO_THREADS, properties) + .ifPresent(builder::setIoThreads); + PropertiesUtil.get(Props.WORKER_THREADS, properties) + .ifPresent(builder::setWorkerThreads); + PropertiesUtil.get(UndertowProps.READ_TIMEOUT, properties) + .ifPresent(value -> builder.setSocketOption(Options.READ_TIMEOUT, value)); + PropertiesUtil.get(UndertowProps.WRITE_TIMEOUT, properties) + .ifPresent(value -> builder.setSocketOption(Options.WRITE_TIMEOUT, value)); + PropertiesUtil.get(UndertowProps.REQUEST_PARSE_TIMEOUT, properties) + .ifPresent(value -> builder.setServerOption(UndertowOptions.REQUEST_PARSE_TIMEOUT, value)); + PropertiesUtil.get(UndertowProps.IDLE_TIMEOUT, properties) + .ifPresent(value -> builder.setServerOption(UndertowOptions.IDLE_TIMEOUT, value)); + PropertiesUtil.get(UndertowProps.NO_REQUEST_TIMEOUT, properties) + .ifPresent(value -> builder.setServerOption(UndertowOptions.NO_REQUEST_TIMEOUT, value)); undertow = builder.build(); @@ -58,4 +65,58 @@ protected boolean stopInternal(long timeout, TimeUnit unit) { private static HttpServerRequest wrap(HttpServerExchange exchange) { return new UndertowHttpServerRequest(exchange); } + + /** + * Specific Undertow properties. + */ + public static class UndertowProps { + + /** + * Configure a read timeout for a socket, in milliseconds. + * + * If the given amount of time elapses without a successful read taking place, the socket's next read will throw a ReadTimeoutException. + * + * @see Options#READ_TIMEOUT + */ + public static final Parameter READ_TIMEOUT = Parameter.integerParameter("readTimeout") + .build(); + + /** + * Configure a write timeout for a socket, in milliseconds. + * + * If the given amount of time elapses without a successful write taking place, the socket's next write will throw a WriteTimeoutException. + * + * @see Options#WRITE_TIMEOUT + */ + public static final Parameter WRITE_TIMEOUT = Parameter.integerParameter("writeTimeout") + .build(); + + /** + * The maximum allowed time of reading HTTP request in milliseconds. + * + * -1 or missing value disables this functionality. + * + * @see UndertowOptions#REQUEST_PARSE_TIMEOUT + */ + public static final Parameter REQUEST_PARSE_TIMEOUT = Parameter.integerParameter("requestParseTimeout") + .build(); + + /** + * The idle timeout in milliseconds after which the channel will be closed. + * + * If the underlying channel already has a read or write timeout set the smaller of the two values will be used for read/write timeouts. + * + * @see UndertowOptions#IDLE_TIMEOUT + */ + public static final Parameter IDLE_TIMEOUT = Parameter.integerParameter("idleTimeout") + .build(); + + /** + * The amount of time the connection can be idle with no current requests before it is closed. + * + * @see UndertowOptions#NO_REQUEST_TIMEOUT + */ + public static final Parameter NO_REQUEST_TIMEOUT = Parameter.integerParameter("noRequestTimeout") + .build(); + } } diff --git a/hercules-util/src/main/java/ru/kontur/vostok/hercules/util/parameter/Parameter.java b/hercules-util/src/main/java/ru/kontur/vostok/hercules/util/parameter/Parameter.java index e7305ce6..51f92d2d 100644 --- a/hercules-util/src/main/java/ru/kontur/vostok/hercules/util/parameter/Parameter.java +++ b/hercules-util/src/main/java/ru/kontur/vostok/hercules/util/parameter/Parameter.java @@ -9,6 +9,8 @@ import ru.kontur.vostok.hercules.util.validation.Validator; import ru.kontur.vostok.hercules.util.validation.Validators; +import java.util.function.Consumer; + /** * Parameter @@ -431,5 +433,16 @@ public boolean isEmpty() { public Parameter parameter() { return Parameter.this; } + + /** + * If a value is present and validation result is ok, performs the given action with the value, otherwise does nothing. + * + * @param consumer Consumer for a value. + */ + public void ifPresent(Consumer consumer) { + if (!isEmpty() && result.isOk()) { + consumer.accept(value); + } + } } } \ No newline at end of file