Skip to content
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

4.x: Concurrency limits module, and support in Helidon WebServer #9295

Merged
merged 10 commits into from
Oct 14, 2024
8 changes: 8 additions & 0 deletions all/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -463,6 +463,10 @@
<groupId>io.helidon.common.features</groupId>
<artifactId>helidon-common-features</artifactId>
</dependency>
<dependency>
<groupId>io.helidon.common.concurrency</groupId>
<artifactId>helidon-common-concurrency-limits</artifactId>
</dependency>
<dependency>
<groupId>io.helidon.dbclient</groupId>
<artifactId>helidon-dbclient</artifactId>
Expand Down Expand Up @@ -996,6 +1000,10 @@
<groupId>io.helidon.webserver</groupId>
<artifactId>helidon-webserver-service-common</artifactId>
</dependency>
<dependency>
<groupId>io.helidon.webserver</groupId>
<artifactId>helidon-webserver-concurrency-limits</artifactId>
</dependency>
<dependency>
<groupId>io.helidon.webserver.testing.junit5</groupId>
<artifactId>helidon-webserver-testing-junit5</artifactId>
Expand Down
10 changes: 10 additions & 0 deletions bom/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -610,6 +610,11 @@
<artifactId>helidon-common-features</artifactId>
<version>${helidon.version}</version>
</dependency>
<dependency>
<groupId>io.helidon.common.concurrency</groupId>
<artifactId>helidon-common-concurrency-limits</artifactId>
<version>${helidon.version}</version>
</dependency>

<!-- db client -->
<dependency>
Expand Down Expand Up @@ -1303,6 +1308,11 @@
<artifactId>helidon-webserver-service-common</artifactId>
<version>${helidon.version}</version>
</dependency>
<dependency>
<groupId>io.helidon.webserver</groupId>
<artifactId>helidon-webserver-concurrency-limits</artifactId>
<version>${helidon.version}</version>
</dependency>
<dependency>
<groupId>io.helidon.webserver.testing.junit5</groupId>
<artifactId>helidon-webserver-testing-junit5</artifactId>
Expand Down
14 changes: 14 additions & 0 deletions common/concurrency/limits/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
Concurrency Limits
-----

This module provides concurrency limits, so we can limit the number of concurrent, in-progress operations (for example in WebServer).

The implemented concurrency limits are:

| Key | Weight | Description |
|-------------|--------|----------------------------------------------------------------------------------------------------------------------|
| `semaphore` | `90` | Semaphore based concurrency limit (highest weight, so the default), if max set to `0`, we have unlimited concurrency |
| `aimd` | `80` | AIMD based limit (additive-increase/multiplicative-decrease) |
| `bulkhead` | `70` | Uses a bulkhead with a queue, implementation provided by `helidon-fault-tolerance` |

Current usage: `helidon-webserver`
117 changes: 117 additions & 0 deletions common/concurrency/limits/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--

Copyright (c) 2024 Oracle and/or its affiliates.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

-->

<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>io.helidon.common.concurrency</groupId>
<artifactId>helidon-common-concurrency-project</artifactId>
<version>4.2.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

<artifactId>helidon-common-concurrency-limits</artifactId>
<name>Helidon Common Concurrency Limits</name>

<dependencies>
<dependency>
<groupId>io.helidon.common</groupId>
<artifactId>helidon-common</artifactId>
</dependency>
<dependency>
<groupId>io.helidon.builder</groupId>
<artifactId>helidon-builder-api</artifactId>
</dependency>
<dependency>
<groupId>io.helidon.common</groupId>
<artifactId>helidon-common-config</artifactId>
</dependency>
<dependency>
<groupId>io.helidon.service</groupId>
<artifactId>helidon-service-registry</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-all</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>io.helidon.codegen</groupId>
<artifactId>helidon-codegen-apt</artifactId>
<version>${helidon.version}</version>
</path>
<path>
<groupId>io.helidon.builder</groupId>
<artifactId>helidon-builder-codegen</artifactId>
<version>${helidon.version}</version>
</path>
<path>
<groupId>io.helidon.config.metadata</groupId>
<artifactId>helidon-config-metadata-codegen</artifactId>
<version>${helidon.version}</version>
</path>
<path>
<groupId>io.helidon.codegen</groupId>
<artifactId>helidon-codegen-helidon-copyright</artifactId>
<version>${helidon.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
<dependencies>
<dependency>
<groupId>io.helidon.codegen</groupId>
<artifactId>helidon-codegen-apt</artifactId>
<version>${helidon.version}</version>
</dependency>
<dependency>
<groupId>io.helidon.builder</groupId>
<artifactId>helidon-builder-codegen</artifactId>
<version>${helidon.version}</version>
</dependency>
<dependency>
<groupId>io.helidon.config.metadata</groupId>
<artifactId>helidon-config-metadata-codegen</artifactId>
<version>${helidon.version}</version>
</dependency>
<dependency>
<groupId>io.helidon.codegen</groupId>
<artifactId>helidon-codegen-helidon-copyright</artifactId>
<version>${helidon.version}</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
/*
* Copyright (c) 2024 Oracle and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.helidon.common.concurrency.limits;

import java.util.concurrent.Callable;
import java.util.concurrent.Semaphore;
import java.util.function.Consumer;

import io.helidon.builder.api.RuntimeType;
import io.helidon.common.config.Config;

/**
* AIMD based limiter.
* <p>
* The additive-increase/multiplicative-decrease (AIMD) algorithm is a feedback control algorithm best known for its use in TCP
* congestion control. AIMD combines linear growth of the congestion window when there is no congestion with an exponential
* reduction when congestion is detected.
*/
@SuppressWarnings("removal")
@RuntimeType.PrototypedBy(AimdLimitConfig.class)
public class AimdLimit implements Limit, SemaphoreLimit, RuntimeType.Api<AimdLimitConfig> {
static final String TYPE = "aimd";

private final AimdLimitConfig config;
private final AimdLimitImpl aimdLimitImpl;

private AimdLimit(AimdLimitConfig config) {
this.config = config;
this.aimdLimitImpl = new AimdLimitImpl(config);
}

/**
* Create a new fluent API builder to construct {@link io.helidon.common.concurrency.limits.AimdLimit}
* instance.
*
* @return fluent API builder
*/
public static AimdLimitConfig.Builder builder() {
return AimdLimitConfig.builder();
}

/**
* Create a new instance with all defaults.
*
* @return a new limit instance
*/
public static AimdLimit create() {
return builder().build();
}

/**
* Create a new instance from configuration.
*
* @param config configuration of the AIMD limit
* @return a new limit instance configured from {@code config}
*/
public static AimdLimit create(Config config) {
return builder()
.config(config)
.build();
}

/**
* Create a new instance from configuration.
*
* @param config configuration of the AIMD limit
* @return a new limit instance configured from {@code config}
*/
public static AimdLimit create(AimdLimitConfig config) {
return new AimdLimit(config);
}

/**
* Create a new instance customizing its configuration.
*
* @param consumer consumer of configuration builder
* @return a new limit instance configured from the builder
*/
public static AimdLimit create(Consumer<AimdLimitConfig.Builder> consumer) {
return builder()
.update(consumer)
.build();
}

@Override
public <T> T invoke(Callable<T> callable) throws Exception {
return aimdLimitImpl.invoke(callable);
}

@Override
public void invoke(Runnable runnable) throws Exception {
aimdLimitImpl.invoke(runnable);
}

@SuppressWarnings("removal")
@Override
public Semaphore semaphore() {
return aimdLimitImpl.semaphore();
}

@Override
public String name() {
return config.name();
}

@Override
public String type() {
return TYPE;
}

@Override
public AimdLimitConfig prototype() {
return config;
}
}
Loading