You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@james.apache.org by bt...@apache.org on 2022/02/14 07:08:49 UTC
[james-project] branch master updated (c345494 -> 8be5e03)
This is an automated email from the ASF dual-hosted git repository.
btellier pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git.
from c345494 [DOCUMENTATION] Example for deploying MUA auto-configuration (#882)
new 05f6833 JAMES-3693 Rate limiting should allow choosing precision
new 8be5e03 JAMES-3693 Add documentation for PerRecipientRateLimitMailet
The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
Summary of changes:
.../mailets/GlobalRateLimitIntegrationTest.java | 1 +
.../mailets/PerSenderRateLimitIntegrationTest.java | 1 +
.../mailet/rate-limiter-redis/mailetcontainer.xml | 1 +
.../rate/limiter/redis/RedisRateLimiter.scala | 12 +++---
.../redis/RedisRateLimiterConfiguration.scala | 8 ++--
.../james/rate/limiter/RedisRateLimiterTest.scala | 2 +-
server/mailet/rate-limiter/README.adoc | 45 +++++++++++++++++++++-
server/mailet/rate-limiter/mailetcontainer.xml | 10 +++++
.../james/rate/limiter/api/RateLimiter.scala | 2 +-
.../rate/limiter/memory/MemoryRateLimiter.scala | 18 +++------
.../james/transport/mailets/EntityType.scala | 5 +++
.../james/transport/mailets/GlobalRateLimit.scala | 11 ++++--
.../transport/mailets/PerRecipientRateLimit.scala | 8 ++--
.../transport/mailets/PerSenderRateLimit.scala | 11 ++++--
.../rate/limiter/api/RateLimiterContract.scala | 25 +++++++-----
.../limiter/memory/MemoryRateLimiterTest.scala | 2 +-
.../transport/mailets/GlobalRateLimitTest.scala | 9 +++++
.../mailets/PerRecipientRateLimitTest.scala | 8 ++++
.../transport/mailets/PerSenderRateLimitTest.scala | 9 +++++
19 files changed, 141 insertions(+), 47 deletions(-)
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@james.apache.org
For additional commands, e-mail: notifications-help@james.apache.org
[james-project] 02/02: JAMES-3693 Add documentation for PerRecipientRateLimitMailet
Posted by bt...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
btellier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git
commit 8be5e03ba2555a378f2b1f2fbc8faecccc114a6d
Author: Quan Tran <hq...@linagora.com>
AuthorDate: Mon Feb 7 16:52:23 2022 +0700
JAMES-3693 Add documentation for PerRecipientRateLimitMailet
---
server/mailet/rate-limiter/README.adoc | 41 +++++++++++++++++++++++++-
server/mailet/rate-limiter/mailetcontainer.xml | 8 +++++
2 files changed, 48 insertions(+), 1 deletion(-)
diff --git a/server/mailet/rate-limiter/README.adoc b/server/mailet/rate-limiter/README.adoc
index 24569fd..2f18b16 100644
--- a/server/mailet/rate-limiter/README.adoc
+++ b/server/mailet/rate-limiter/README.adoc
@@ -109,4 +109,43 @@ For instance, to apply all the examples given above:
</mailet>
----
-When the rate is exceeded, all mails will be moved to processor *tooMuchMails* which send a bounce message notifies that user exceeded the rate limit.
\ No newline at end of file
+When the rate is exceeded, all mails will be moved to processor *tooMuchMails* which send a bounce message notifies that user exceeded the rate limit.
+
+=== PerRecipientRateLimitMailet
+
+*PerRecipientRateLimitMailet* allows defining and enforcing rate limits for the recipients of matching emails.
+
+This allows writing rules like:
+
+- A recipient can receive 10 emails per hour
+- A recipient can receive 100 MB of emails per hour
+
+Depending on its position and the matcher it is being combined with, those rate limiting rules could be applied to
+submitted emails, received emails or emitted email being relayed to third parties.
+
+Here are supported configuration parameters:
+
+- *keyPrefix*: An optional key prefix to apply to rate limiting. Choose distinct values if you specify
+this mailet twice within your `mailetcontainer.xml` file. Defaults to none.
+- *exceededProcessor*: Processor to which emails whose rate is exceeded should be redirected to. Defaults to error.
+Use this to customize the behaviour upon exceeded rate.
+- *duration*: Duration during which the rate limiting shall be applied. Compulsory, must be a valid duration of at least one second. Supported units includes s (second), m (minute), h (hour), d (day).
+- *precision*: Defines the time precision that will be used to approximate the sliding window. A lower duration increases precision but requests more computing power. The precision must be greater than 1 second. Optional, default to duration means fixed window counters. Supported units includes s (second), m (minute), h (hour), d (day).
+- *count*: Count of emails allowed for a given recipient during duration. Optional, if unspecified this rate limit is not applied.
+- *size*: Size of emails allowed for a given recipient during duration. Optional, if unspecified this rate limit is not applied. Supported units : B ( 2^0 ), K ( 2^10 ), M ( 2^20 ), G ( 2^30 ), defaults to B.
+
+
+For instance, to apply all the examples given above:
+
+----
+<mailet matcher="All" class="PerRecipientRateLimitMailet">
+ <keyPrefix>myPrefix</keyPrefix>
+ <duration>1h</duration>
+ <precision>1h</precision>
+ <count>10</count>
+ <size>100M</size>
+ <exceededProcessor>tooMuchMails</exceededProcessor>
+</mailet>
+----
+
+When the rate is exceeded, a new mail with recipients that are exceeded recipients will be moved to processor *tooMuchMails* which send a bounce message notifies that the rate limit exceeded.
\ No newline at end of file
diff --git a/server/mailet/rate-limiter/mailetcontainer.xml b/server/mailet/rate-limiter/mailetcontainer.xml
index 6bcdb5f..10aa8e3 100644
--- a/server/mailet/rate-limiter/mailetcontainer.xml
+++ b/server/mailet/rate-limiter/mailetcontainer.xml
@@ -121,6 +121,14 @@
<totalSize>200M</totalSize>
<exceededProcessor>tooMuchMails</exceededProcessor>
</mailet>
+ <mailet matcher="All" class="PerRecipientRateLimitMailet">
+ <keyPrefix>myPrefix</keyPrefix>
+ <duration>1h</duration>
+ <precision>1h</precision>
+ <count>10</count>
+ <size>100M</size>
+ <exceededProcessor>tooMuchMails</exceededProcessor>
+ </mailet>
<mailet match="All" class="RemoteDelivery">
<outgoingQueue>outgoing</outgoingQueue>
<delayTime>5000, 100000, 500000</delayTime>
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@james.apache.org
For additional commands, e-mail: notifications-help@james.apache.org
[james-project] 01/02: JAMES-3693 Rate limiting should allow choosing precision
Posted by bt...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
btellier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git
commit 05f6833e81f6b6fa2e8d081fc6dd369699b5bb33
Author: Quan Tran <hq...@linagora.com>
AuthorDate: Mon Feb 7 15:40:38 2022 +0700
JAMES-3693 Rate limiting should allow choosing precision
---
.../mailets/GlobalRateLimitIntegrationTest.java | 1 +
.../mailets/PerSenderRateLimitIntegrationTest.java | 1 +
.../mailet/rate-limiter-redis/mailetcontainer.xml | 1 +
.../rate/limiter/redis/RedisRateLimiter.scala | 12 +++++------
.../redis/RedisRateLimiterConfiguration.scala | 8 +++----
.../james/rate/limiter/RedisRateLimiterTest.scala | 2 +-
server/mailet/rate-limiter/README.adoc | 4 ++++
server/mailet/rate-limiter/mailetcontainer.xml | 2 ++
.../james/rate/limiter/api/RateLimiter.scala | 2 +-
.../rate/limiter/memory/MemoryRateLimiter.scala | 18 +++++-----------
.../james/transport/mailets/EntityType.scala | 5 +++++
.../james/transport/mailets/GlobalRateLimit.scala | 11 +++++++---
.../transport/mailets/PerRecipientRateLimit.scala | 8 ++++---
.../transport/mailets/PerSenderRateLimit.scala | 11 +++++++---
.../rate/limiter/api/RateLimiterContract.scala | 25 +++++++++++++---------
.../limiter/memory/MemoryRateLimiterTest.scala | 2 +-
.../transport/mailets/GlobalRateLimitTest.scala | 9 ++++++++
.../mailets/PerRecipientRateLimitTest.scala | 8 +++++++
.../transport/mailets/PerSenderRateLimitTest.scala | 9 ++++++++
19 files changed, 93 insertions(+), 46 deletions(-)
diff --git a/server/mailet/integration-testing/src/test/java/org/apache/james/transport/mailets/GlobalRateLimitIntegrationTest.java b/server/mailet/integration-testing/src/test/java/org/apache/james/transport/mailets/GlobalRateLimitIntegrationTest.java
index c55396a..f8d31cb 100644
--- a/server/mailet/integration-testing/src/test/java/org/apache/james/transport/mailets/GlobalRateLimitIntegrationTest.java
+++ b/server/mailet/integration-testing/src/test/java/org/apache/james/transport/mailets/GlobalRateLimitIntegrationTest.java
@@ -92,6 +92,7 @@ public class GlobalRateLimitIntegrationTest {
.matcher(All.class)
.mailet(GlobalRateLimit.class)
.addProperty("duration", "100s")
+ .addProperty("precision", "1s")
.addProperty("count", "2")
.addProperty("recipients", "3")
.addProperty("size", "13K")
diff --git a/server/mailet/integration-testing/src/test/java/org/apache/james/transport/mailets/PerSenderRateLimitIntegrationTest.java b/server/mailet/integration-testing/src/test/java/org/apache/james/transport/mailets/PerSenderRateLimitIntegrationTest.java
index ca15afa..ec4fb55 100644
--- a/server/mailet/integration-testing/src/test/java/org/apache/james/transport/mailets/PerSenderRateLimitIntegrationTest.java
+++ b/server/mailet/integration-testing/src/test/java/org/apache/james/transport/mailets/PerSenderRateLimitIntegrationTest.java
@@ -82,6 +82,7 @@ public class PerSenderRateLimitIntegrationTest {
.matcher(All.class)
.mailet(PerSenderRateLimit.class)
.addProperty("duration", "100s")
+ .addProperty("precision", "1s")
.addProperty("count", "1")
.addProperty("recipients", "2")
.addProperty("size", "6K")
diff --git a/server/mailet/rate-limiter-redis/mailetcontainer.xml b/server/mailet/rate-limiter-redis/mailetcontainer.xml
index 8804b31..f790745 100644
--- a/server/mailet/rate-limiter-redis/mailetcontainer.xml
+++ b/server/mailet/rate-limiter-redis/mailetcontainer.xml
@@ -104,6 +104,7 @@
<mailet matcher="All" class="PerSenderRateLimit">
<keyPrefix>myPrefix</keyPrefix>
<duration>1h</duration>
+ <precision>1h</precision>
<count>10</count>
<recipients>20</recipients>
<size>100M</size>
diff --git a/server/mailet/rate-limiter-redis/src/main/scala/org/apache/james/rate/limiter/redis/RedisRateLimiter.scala b/server/mailet/rate-limiter-redis/src/main/scala/org/apache/james/rate/limiter/redis/RedisRateLimiter.scala
index f2b3f7b..d9aa0fc 100644
--- a/server/mailet/rate-limiter-redis/src/main/scala/org/apache/james/rate/limiter/redis/RedisRateLimiter.scala
+++ b/server/mailet/rate-limiter-redis/src/main/scala/org/apache/james/rate/limiter/redis/RedisRateLimiter.scala
@@ -19,6 +19,8 @@
package org.apache.james.rate.limiter.redis
+import java.time.Duration
+
import com.google.inject.{AbstractModule, Provides}
import es.moki.ratelimitj.core.limiter.request.{AbstractRequestRateLimiterFactory, ReactiveRequestRateLimiter, RequestLimitRule}
import es.moki.ratelimitj.redis.request.{RedisClusterRateLimiterFactory, RedisSlidingWindowRequestRateLimiter, RedisRateLimiterFactory => RedisSingleInstanceRateLimitjFactory}
@@ -51,16 +53,14 @@ class RedisRateLimiterFactory @Inject()(redisConfiguration: RedisRateLimiterConf
new RedisSingleInstanceRateLimitjFactory(RedisClient.create(redisConfiguration.redisURI.value.last))
}
- override def withSpecification(rules: Rules): RateLimiter =
+ override def withSpecification(rules: Rules, precision: Option[Duration]): RateLimiter =
RedisRateLimiter(rateLimitjFactory.getInstanceReactive(rules.rules
.map(convert)
- .map(withPrecision)
+ .map(withPrecision(_, precision))
.toSet.asJava))
- private def withPrecision(rule: RequestLimitRule): RequestLimitRule =
- redisConfiguration.windowPrecision
- .map(rule.withPrecision)
- .getOrElse(rule)
+ private def withPrecision(rule: RequestLimitRule, precision: Option[Duration]): RequestLimitRule =
+ precision.map(rule.withPrecision).getOrElse(rule)
private def convert(rule: Rule): RequestLimitRule = RequestLimitRule.of(rule.duration, rule.quantity.value)
}
diff --git a/server/mailet/rate-limiter-redis/src/main/scala/org/apache/james/rate/limiter/redis/RedisRateLimiterConfiguration.scala b/server/mailet/rate-limiter-redis/src/main/scala/org/apache/james/rate/limiter/redis/RedisRateLimiterConfiguration.scala
index 1bd9be1..922bd09 100644
--- a/server/mailet/rate-limiter-redis/src/main/scala/org/apache/james/rate/limiter/redis/RedisRateLimiterConfiguration.scala
+++ b/server/mailet/rate-limiter-redis/src/main/scala/org/apache/james/rate/limiter/redis/RedisRateLimiterConfiguration.scala
@@ -19,8 +19,6 @@
package org.apache.james.rate.limiter.redis
-import java.time.Duration
-
import com.google.common.base.Preconditions
import eu.timepit.refined
import eu.timepit.refined.api.Refined
@@ -33,9 +31,9 @@ object RedisRateLimiterConfiguration {
def from(config: Configuration): RedisRateLimiterConfiguration =
from(config.getString("redisURL"))
- def from(redisUri: String, windowPrecision: Option[Duration] = None): RedisRateLimiterConfiguration = {
+ def from(redisUri: String): RedisRateLimiterConfiguration = {
Preconditions.checkArgument(redisUri != null && !redisUri.isBlank)
- RedisRateLimiterConfiguration(RedisUris.from(redisUri), windowPrecision)
+ RedisRateLimiterConfiguration(RedisUris.from(redisUri))
}
}
@@ -58,4 +56,4 @@ object RedisUris {
def from(value: String): RedisUris = liftOrThrow(value.split(',').toList.map(RedisURI.create))
}
-case class RedisRateLimiterConfiguration(redisURI: RedisUris, windowPrecision: Option[Duration] = None)
+case class RedisRateLimiterConfiguration(redisURI: RedisUris)
diff --git a/server/mailet/rate-limiter-redis/src/test/java/org/apache/james/rate/limiter/RedisRateLimiterTest.scala b/server/mailet/rate-limiter-redis/src/test/java/org/apache/james/rate/limiter/RedisRateLimiterTest.scala
index 2e9949e..ff378c0 100644
--- a/server/mailet/rate-limiter-redis/src/test/java/org/apache/james/rate/limiter/RedisRateLimiterTest.scala
+++ b/server/mailet/rate-limiter-redis/src/test/java/org/apache/james/rate/limiter/RedisRateLimiterTest.scala
@@ -33,7 +33,7 @@ class RedisRateLimiterTest extends RateLimiterContract {
@BeforeEach
def setup(redis: DockerRedis): Unit = {
- redisRateLimiterConfiguration = RedisRateLimiterConfiguration.from(redis.redisURI().toString, Some(Duration.ofSeconds(1)))
+ redisRateLimiterConfiguration = RedisRateLimiterConfiguration.from(redis.redisURI().toString)
}
override def testee(): RateLimiterFactory = new RedisRateLimiterFactory(redisRateLimiterConfiguration)
diff --git a/server/mailet/rate-limiter/README.adoc b/server/mailet/rate-limiter/README.adoc
index b9ca046..24569fd 100644
--- a/server/mailet/rate-limiter/README.adoc
+++ b/server/mailet/rate-limiter/README.adoc
@@ -40,6 +40,7 @@ Here are supported configuration parameters:
- *exceededProcessor*: Processor to which emails whose rate is exceeded should be redirected to. Defaults to error.
Use this to customize the behaviour upon exceeded rate.
- *duration*: Duration during which the rate limiting shall be applied. Compulsory, must be a valid duration of at least one second. Supported units includes s (second), m (minute), h (hour), d (day).
+ - *precision*: Defines the time precision that will be used to approximate the sliding window. A lower duration increases precision but requests more computing power. The precision must be greater than 1 second. Optional, default to duration means fixed window counters. Supported units includes s (second), m (minute), h (hour), d (day).
- *count*: Count of emails allowed for a given sender during duration. Optional, if unspecified this rate limit is not applied.
- *recipients*: Count of recipients allowed for a given sender during duration. Optional, if unspecified this rate limit is not applied.
- *size*: Size of emails allowed for a given sender during duration (each email count one time, regardless of recipient count). Optional, if unspecified this rate limit is not applied. Supported units : B ( 2^0 ), K ( 2^10 ), M ( 2^20 ), G ( 2^30 ), defaults to B.
@@ -53,6 +54,7 @@ For instance, to apply all the examples given above:
<mailet matcher="All" class="PerSenderRateLimit">
<keyPrefix>myPrefix</keyPrefix>
<duration>1h</duration>
+ <precision>1h</precision>
<count>10</count>
<recipients>20</recipients>
<size>100M</size>
@@ -84,6 +86,7 @@ this mailet twice within your `mailetcontainer.xml` file. Defaults to none.
- *exceededProcessor*: Processor to which emails whose rate is exceeded should be redirected to. Defaults to error.
Use this to customize the behaviour upon exceeded rate.
- *duration*: Duration during which the rate limiting shall be applied. Compulsory, must be a valid duration of at least one second. Supported units includes s (second), m (minute), h (hour), d (day).
+- *precision*: Defines the time precision that will be used to approximate the sliding window. A lower duration increases precision but requests more computing power. The precision must be greater than 1 second. Optional, default to duration means fixed window counters. Supported units includes s (second), m (minute), h (hour), d (day).
- *count*: Count of emails allowed for all users during duration. Optional, if unspecified this rate limit is not applied.
- *recipients*: Count of recipients allowed for all users during duration. Optional, if unspecified this rate limit is not applied.
- *size*: Size of emails allowed for all users during duration (each email count one time, regardless of recipient count). Optional, if unspecified this rate limit is not applied. Supported units : B ( 2^0 ), K ( 2^10 ), M ( 2^20 ), G ( 2^30 ), defaults to B.
@@ -97,6 +100,7 @@ For instance, to apply all the examples given above:
<mailet matcher="All" class="GlobalRateLimit">
<keyPrefix>myPrefix</keyPrefix>
<duration>1h</duration>
+ <precision>1h</precision>
<count>100</count>
<recipients>200</recipients>
<size>1000M</size>
diff --git a/server/mailet/rate-limiter/mailetcontainer.xml b/server/mailet/rate-limiter/mailetcontainer.xml
index 0bb5f36..6bcdb5f 100644
--- a/server/mailet/rate-limiter/mailetcontainer.xml
+++ b/server/mailet/rate-limiter/mailetcontainer.xml
@@ -104,6 +104,7 @@
<mailet matcher="All" class="GlobalRateLimit">
<keyPrefix>myPrefix</keyPrefix>
<duration>1h</duration>
+ <precision>1h</precision>
<count>100</count>
<recipients>200</recipients>
<size>1000M</size>
@@ -113,6 +114,7 @@
<mailet matcher="All" class="PerSenderRateLimit">
<keyPrefix>myPrefix</keyPrefix>
<duration>1h</duration>
+ <precision>1h</precision>
<count>10</count>
<recipients>20</recipients>
<size>100M</size>
diff --git a/server/mailet/rate-limiter/src/main/scala/org/apache/james/rate/limiter/api/RateLimiter.scala b/server/mailet/rate-limiter/src/main/scala/org/apache/james/rate/limiter/api/RateLimiter.scala
index 1be822e..c02c1aa 100644
--- a/server/mailet/rate-limiter/src/main/scala/org/apache/james/rate/limiter/api/RateLimiter.scala
+++ b/server/mailet/rate-limiter/src/main/scala/org/apache/james/rate/limiter/api/RateLimiter.scala
@@ -74,7 +74,7 @@ trait RateLimiter {
}
trait RateLimiterFactory {
- def withSpecification(rules: Rules): RateLimiter
+ def withSpecification(rules: Rules, precision: Option[Duration]): RateLimiter
}
sealed trait RateLimitingResult {
diff --git a/server/mailet/rate-limiter/src/main/scala/org/apache/james/rate/limiter/memory/MemoryRateLimiter.scala b/server/mailet/rate-limiter/src/main/scala/org/apache/james/rate/limiter/memory/MemoryRateLimiter.scala
index 9b62411..813b411 100644
--- a/server/mailet/rate-limiter/src/main/scala/org/apache/james/rate/limiter/memory/MemoryRateLimiter.scala
+++ b/server/mailet/rate-limiter/src/main/scala/org/apache/james/rate/limiter/memory/MemoryRateLimiter.scala
@@ -24,7 +24,6 @@ import java.time.Duration
import com.google.inject.AbstractModule
import es.moki.ratelimitj.core.limiter.request.{RequestLimitRule, RequestRateLimiter}
import es.moki.ratelimitj.inmemory.request.InMemorySlidingWindowRequestRateLimiter
-import javax.inject.Inject
import org.apache.james.rate.limiter.api.Increment.Increment
import org.apache.james.rate.limiter.api.{AcceptableRate, RateExceeded, RateLimiter, RateLimiterFactory, RateLimitingKey, RateLimitingResult, Rule, Rules}
import org.reactivestreams.Publisher
@@ -38,22 +37,15 @@ class MemoryRateLimiterModule() extends AbstractModule {
.to(classOf[MemoryRateLimiterFactory])
}
-class MemoryRateLimiterFactory (precision: Option[Duration] = None) extends RateLimiterFactory {
- @Inject()
- def this() = {
- this(None)
- }
-
- override def withSpecification(rules: Rules): RateLimiter = {
+class MemoryRateLimiterFactory() extends RateLimiterFactory {
+ override def withSpecification(rules: Rules, precision: Option[Duration]): RateLimiter =
MemoryRateLimiter(new InMemorySlidingWindowRequestRateLimiter(rules.rules
.map(convert)
- .map(withPrecision)
+ .map(withPrecision(_, precision))
.toSet.asJava))
- }
- private def withPrecision(rule: RequestLimitRule): RequestLimitRule =
- precision.map(rule.withPrecision)
- .getOrElse(rule)
+ private def withPrecision(rule: RequestLimitRule, precision: Option[Duration]): RequestLimitRule =
+ precision.map(rule.withPrecision).getOrElse(rule)
private def convert(rule: Rule): RequestLimitRule = RequestLimitRule.of(rule.duration, rule.quantity.value)
}
diff --git a/server/mailet/rate-limiter/src/main/scala/org/apache/james/transport/mailets/EntityType.scala b/server/mailet/rate-limiter/src/main/scala/org/apache/james/transport/mailets/EntityType.scala
index 372ee54..ca65489 100644
--- a/server/mailet/rate-limiter/src/main/scala/org/apache/james/transport/mailets/EntityType.scala
+++ b/server/mailet/rate-limiter/src/main/scala/org/apache/james/transport/mailets/EntityType.scala
@@ -38,6 +38,11 @@ object DurationParsingUtil {
.getOrElse(throw new IllegalArgumentException("'duration' is compulsory"))
}
+object PrecisionParsingUtil {
+ def parsePrecision(mailetConfig: MailetConfig): Option[Duration] = Option(mailetConfig.getInitParameter("precision"))
+ .map(string => DurationParser.parse(string, ChronoUnit.SECONDS))
+}
+
sealed trait EntityType {
def asString(): String
diff --git a/server/mailet/rate-limiter/src/main/scala/org/apache/james/transport/mailets/GlobalRateLimit.scala b/server/mailet/rate-limiter/src/main/scala/org/apache/james/transport/mailets/GlobalRateLimit.scala
index 1b891b0..e06ff72 100644
--- a/server/mailet/rate-limiter/src/main/scala/org/apache/james/transport/mailets/GlobalRateLimit.scala
+++ b/server/mailet/rate-limiter/src/main/scala/org/apache/james/transport/mailets/GlobalRateLimit.scala
@@ -66,6 +66,7 @@ case class GlobalRateLimiter(rateLimiter: Option[RateLimiter], keyPrefix: Option
* <li><b>exceededProcessor</b>: Processor to which emails whose rate is exceeded should be redirected to. Defaults to error.
* Use this to customize the behaviour upon exceeded rate.</li>
* <li><b>duration</b>: Duration during which the rate limiting shall be applied. Compulsory, must be a valid duration of at least one second. Supported units includes s (second), m (minute), h (hour), d (day).</li>
+ * <li><b>precision</b>: Defines the time precision that will be used to approximate the sliding window. A lower duration increases precision but requests more computing power. The precision must be greater than 1 second. Optional, default to duration means fixed window counters. Supported units includes s (second), m (minute), h (hour), d (day).</li>
* <li><b>count</b>: Count of emails allowed for all users during duration. Optional, if unspecified this rate limit is not applied.</li>
* <li><b>recipients</b>: Count of recipients allowed for all users during duration. Optional, if unspecified this rate limit is not applied.</li>
* <li><b>size</b>: Size of emails allowed for all users during duration (each email count one time, regardless of recipient count). Optional, if unspecified this rate limit is not applied. Supported units : B ( 2^0 ), K ( 2^10 ), M ( 2^20 ), G ( 2^30 ), defaults to B.</li>
@@ -79,6 +80,7 @@ case class GlobalRateLimiter(rateLimiter: Option[RateLimiter], keyPrefix: Option
* <mailet matcher="All" class="GlobalRateLimit">
* <keyPrefix>myPrefix</keyPrefix>
* <duration>1h</duration>
+ * <precision>1h</precision>
* <count>10</count>
* <recipients>20</recipients>
* <size>100M</size>
@@ -105,11 +107,12 @@ class GlobalRateLimit @Inject()(rateLimiterFactory: RateLimiterFactory) extends
override def init(): Unit = {
val duration: Duration = parseDuration()
+ val precision: Option[Duration] = parsePrecision()
keyPrefix = Option(getInitParameter("keyPrefix")).map(KeyPrefix)
exceededProcessor = getInitParameter("exceededProcessor", Mail.ERROR)
- def globalRateLimiter(entityType: EntityType): GlobalRateLimiter = createRateLimiter(rateLimiterFactory, entityType, keyPrefix, duration)
+ def globalRateLimiter(entityType: EntityType): GlobalRateLimiter = createRateLimiter(rateLimiterFactory, entityType, keyPrefix, duration, precision)
countRateLimiter = globalRateLimiter(Count)
recipientsRateLimiter = globalRateLimiter(RecipientsType)
@@ -118,6 +121,7 @@ class GlobalRateLimit @Inject()(rateLimiterFactory: RateLimiterFactory) extends
}
def parseDuration(): Duration = DurationParsingUtil.parseDuration(getMailetConfig)
+ def parsePrecision(): Option[Duration] = PrecisionParsingUtil.parsePrecision(getMailetConfig)
override def service(mail: Mail): Unit = {
val pivot: RateLimitingResult = AcceptableRate
@@ -134,9 +138,10 @@ class GlobalRateLimit @Inject()(rateLimiterFactory: RateLimiterFactory) extends
}
}
- private def createRateLimiter(rateLimiterFactory: RateLimiterFactory, entityType: EntityType, keyPrefix: Option[KeyPrefix], duration: Duration): GlobalRateLimiter =
+ private def createRateLimiter(rateLimiterFactory: RateLimiterFactory, entityType: EntityType, keyPrefix: Option[KeyPrefix],
+ duration: Duration, precision: Option[Duration]): GlobalRateLimiter =
GlobalRateLimiter(rateLimiter = entityType.extractRules(duration, getMailetConfig)
- .map(rateLimiterFactory.withSpecification),
+ .map(rateLimiterFactory.withSpecification(_, precision)),
keyPrefix = keyPrefix,
entityType = entityType)
}
diff --git a/server/mailet/rate-limiter/src/main/scala/org/apache/james/transport/mailets/PerRecipientRateLimit.scala b/server/mailet/rate-limiter/src/main/scala/org/apache/james/transport/mailets/PerRecipientRateLimit.scala
index a8b05a1..de0c8c8 100644
--- a/server/mailet/rate-limiter/src/main/scala/org/apache/james/transport/mailets/PerRecipientRateLimit.scala
+++ b/server/mailet/rate-limiter/src/main/scala/org/apache/james/transport/mailets/PerRecipientRateLimit.scala
@@ -97,10 +97,11 @@ class PerRecipientRateLimit @Inject()(rateLimiterFactory: RateLimiterFactory) ex
override def init(): Unit = {
val duration: Duration = parseDuration()
+ val precision: Option[Duration] = parsePrecision()
val keyPrefix: Option[KeyPrefix] = Option(getInitParameter("keyPrefix")).map(KeyPrefix)
exceededProcessor = getInitParameter("exceededProcessor", Mail.ERROR)
- def perRecipientRateLimiter(entityType: EntityType): Option[PerRecipientRateLimiter] = createRateLimiter(entityType, duration, rateLimiterFactory, keyPrefix)
+ def perRecipientRateLimiter(entityType: EntityType): Option[PerRecipientRateLimiter] = createRateLimiter(entityType, duration, precision, rateLimiterFactory, keyPrefix)
rateLimiters = Seq(perRecipientRateLimiter(Size),
perRecipientRateLimiter(Count))
@@ -131,11 +132,12 @@ class PerRecipientRateLimit @Inject()(rateLimiterFactory: RateLimiterFactory) ex
@VisibleForTesting
def parseDuration(): Duration = DurationParsingUtil.parseDuration(getMailetConfig)
+ def parsePrecision(): Option[Duration] = PrecisionParsingUtil.parsePrecision(getMailetConfig)
- private def createRateLimiter(entityType: EntityType, duration: Duration,
+ private def createRateLimiter(entityType: EntityType, duration: Duration, precision: Option[Duration],
rateLimiterFactory: RateLimiterFactory, keyPrefix: Option[KeyPrefix]): Option[PerRecipientRateLimiter] =
entityType.extractRules(duration, getMailetConfig)
- .map(rateLimiterFactory.withSpecification)
+ .map(rateLimiterFactory.withSpecification(_, precision))
.map(PerRecipientRateLimiter(_, keyPrefix, entityType))
diff --git a/server/mailet/rate-limiter/src/main/scala/org/apache/james/transport/mailets/PerSenderRateLimit.scala b/server/mailet/rate-limiter/src/main/scala/org/apache/james/transport/mailets/PerSenderRateLimit.scala
index cc4129b..b981e56 100644
--- a/server/mailet/rate-limiter/src/main/scala/org/apache/james/transport/mailets/PerSenderRateLimit.scala
+++ b/server/mailet/rate-limiter/src/main/scala/org/apache/james/transport/mailets/PerSenderRateLimit.scala
@@ -66,6 +66,7 @@ case class SenderKey(keyPrefix: Option[KeyPrefix], entityType: EntityType, mailA
* <li><b>exceededProcessor</b>: Processor to which emails whose rate is exceeded should be redirected to. Defaults to error.
* Use this to customize the behaviour upon exceeded rate.</li>
* <li><b>duration</b>: Duration during which the rate limiting shall be applied. Compulsory, must be a valid duration of at least one second. Supported units includes s (second), m (minute), h (hour), d (day).</li>
+ * <li><b>precision</b>: Defines the time precision that will be used to approximate the sliding window. A lower duration increases precision but requests more computing power. The precision must be greater than 1 second. Optional, default to duration means fixed window counters. Supported units includes s (second), m (minute), h (hour), d (day).</li>
* <li><b>count</b>: Count of emails allowed for a given sender during duration. Optional, if unspecified this rate limit is not applied.</li>
* <li><b>recipients</b>: Count of recipients allowed for a given sender during duration. Optional, if unspecified this rate limit is not applied.</li>
* <li><b>size</b>: Size of emails allowed for a given sender during duration (each email count one time, regardless of recipient count). Optional, if unspecified this rate limit is not applied. Supported units : B ( 2^0 ), K ( 2^10 ), M ( 2^20 ), G ( 2^30 ), defaults to B.</li>
@@ -79,6 +80,7 @@ case class SenderKey(keyPrefix: Option[KeyPrefix], entityType: EntityType, mailA
* <mailet matcher="All" class="PerSenderRateLimit">
* <keyPrefix>myPrefix</keyPrefix>
* <duration>1h</duration>
+ * <precision>1h</precision>
* <count>10</count>
* <recipients>20</recipients>
* <size>100M</size>
@@ -105,11 +107,12 @@ class PerSenderRateLimit @Inject()(rateLimiterFactory: RateLimiterFactory) exten
override def init(): Unit = {
val duration: Duration = parseDuration()
+ val precision: Option[Duration] = parsePrecision()
keyPrefix = Option(getInitParameter("keyPrefix")).map(KeyPrefix)
exceededProcessor = getInitParameter("exceededProcessor", Mail.ERROR)
- def perSenderRateLimiter(entityType: EntityType): PerSenderRateLimiter = createRateLimiter(rateLimiterFactory, entityType, keyPrefix, duration)
+ def perSenderRateLimiter(entityType: EntityType): PerSenderRateLimiter = createRateLimiter(rateLimiterFactory, entityType, keyPrefix, duration, precision)
countRateLimiter = perSenderRateLimiter(Count)
recipientsRateLimiter = perSenderRateLimiter(RecipientsType)
@@ -119,6 +122,7 @@ class PerSenderRateLimit @Inject()(rateLimiterFactory: RateLimiterFactory) exten
@VisibleForTesting
def parseDuration(): Duration = DurationParsingUtil.parseDuration(getMailetConfig)
+ def parsePrecision(): Option[Duration] = PrecisionParsingUtil.parsePrecision(getMailetConfig)
override def service(mail: Mail): Unit = mail.getMaybeSender
.asOptional()
@@ -141,9 +145,10 @@ class PerSenderRateLimit @Inject()(rateLimiterFactory: RateLimiterFactory) exten
}
}
- private def createRateLimiter(rateLimiterFactory: RateLimiterFactory, entityType: EntityType, keyPrefix: Option[KeyPrefix], duration: Duration): PerSenderRateLimiter =
+ private def createRateLimiter(rateLimiterFactory: RateLimiterFactory, entityType: EntityType, keyPrefix: Option[KeyPrefix],
+ duration: Duration, precision: Option[Duration]): PerSenderRateLimiter =
PerSenderRateLimiter(rateLimiter = entityType.extractRules(duration, getMailetConfig)
- .map(rateLimiterFactory.withSpecification),
+ .map(rateLimiterFactory.withSpecification(_, precision)),
keyPrefix = keyPrefix,
entityType = entityType)
}
diff --git a/server/mailet/rate-limiter/src/test/scala/org/apache/james/rate/limiter/api/RateLimiterContract.scala b/server/mailet/rate-limiter/src/test/scala/org/apache/james/rate/limiter/api/RateLimiterContract.scala
index 722b82c..cd9cab4 100644
--- a/server/mailet/rate-limiter/src/test/scala/org/apache/james/rate/limiter/api/RateLimiterContract.scala
+++ b/server/mailet/rate-limiter/src/test/scala/org/apache/james/rate/limiter/api/RateLimiterContract.scala
@@ -22,6 +22,7 @@ package org.apache.james.rate.limiter.api
import java.time.Duration
import eu.timepit.refined.auto._
+import org.apache.james.rate.limiter.api.RateLimiterContract.SLIDING_WIDOW_PRECISION
import org.assertj.core.api.Assertions.assertThat
import org.assertj.core.api.SoftAssertions
import org.junit.jupiter.api.Test
@@ -31,6 +32,10 @@ case class TestKey(value: String) extends RateLimitingKey {
override def asString(): String = value
}
+object RateLimiterContract {
+ val SLIDING_WIDOW_PRECISION: Option[Duration] = Some(Duration.ofSeconds(1))
+}
+
trait RateLimiterContract {
private val rules = Rules(Seq(Rule(4L, Duration.ofSeconds(2))))
@@ -40,7 +45,7 @@ trait RateLimiterContract {
@Test
def subsequentRequestsBelowLimitsWithoutPauseShouldBeAcceptable(): Unit = {
- val rateLimiter = testee().withSpecification(rules)
+ val rateLimiter = testee().withSpecification(rules, SLIDING_WIDOW_PRECISION)
SoftAssertions.assertSoftly(softly => {
(1 to 4).foreach(_ => {
@@ -52,7 +57,7 @@ trait RateLimiterContract {
@Test
def subsequentRequestsAtLimitsWithoutPauseShouldBeAcceptable(): Unit = {
- val rateLimiter = testee().withSpecification(rules)
+ val rateLimiter = testee().withSpecification(rules, SLIDING_WIDOW_PRECISION)
val actual: RateLimitingResult = SMono(rateLimiter.rateLimit(TestKey("key1"), 4)).block()
assertThat(actual).isEqualTo(AcceptableRate)
@@ -60,7 +65,7 @@ trait RateLimiterContract {
@Test
def subsequentRequestsOverLimitsWithoutPauseShouldBeExceeded(): Unit = {
- val rateLimiter = testee().withSpecification(rules)
+ val rateLimiter = testee().withSpecification(rules, SLIDING_WIDOW_PRECISION)
val actual: RateLimitingResult = SMono(rateLimiter.rateLimit(TestKey("key1"), 5)).block()
assertThat(actual).isEqualTo(RateExceeded)
@@ -68,7 +73,7 @@ trait RateLimiterContract {
@Test
def subsequentRequestsByBlockOverLimitsWithoutPauseShouldBeExceeded(): Unit = {
- val rateLimiter = testee().withSpecification(rules)
+ val rateLimiter = testee().withSpecification(rules, SLIDING_WIDOW_PRECISION)
SMono(rateLimiter.rateLimit(TestKey("key1"), 2)).block()
val actual: RateLimitingResult = SMono(rateLimiter.rateLimit(TestKey("key1"), 3)).block()
@@ -77,7 +82,7 @@ trait RateLimiterContract {
@Test
def subsequentRequestsByBlockOverLimitsWithSmallPauseShouldBeExceeded(): Unit = {
- val rateLimiter = testee().withSpecification(Rules(Seq(Rule(4L, Duration.ofSeconds(20)))))
+ val rateLimiter = testee().withSpecification(Rules(Seq(Rule(4L, Duration.ofSeconds(20)))), SLIDING_WIDOW_PRECISION)
SMono(rateLimiter.rateLimit(TestKey("key1"), 2)).block()
sleep(Duration.ofSeconds(1))
@@ -87,7 +92,7 @@ trait RateLimiterContract {
@Test
def subsequentRequestsByBlockOverLimitsWithLongPauseShouldBeAcceptable(): Unit = {
- val rateLimiter = testee().withSpecification(rules)
+ val rateLimiter = testee().withSpecification(rules, SLIDING_WIDOW_PRECISION)
SMono(rateLimiter.rateLimit(TestKey("key1"), 2)).block()
sleep(Duration.ofSeconds(3))
@@ -97,7 +102,7 @@ trait RateLimiterContract {
@Test
def rateLimitingShouldBePartitionedByKey(): Unit = {
- val rateLimiter = testee().withSpecification(rules)
+ val rateLimiter = testee().withSpecification(rules, SLIDING_WIDOW_PRECISION)
SMono(rateLimiter.rateLimit(TestKey("key1"), 2)).block()
val actual: RateLimitingResult = SMono(rateLimiter.rateLimit(TestKey("key2"), 3)).block()
@@ -108,7 +113,7 @@ trait RateLimiterContract {
def shouldFailWhenUpperLimitExceeded(): Unit = {
val rateLimiter = testee().withSpecification(Rules(Seq(
Rule(1L, Duration.ofSeconds(1)),
- Rule(2L, Duration.ofSeconds(20)))))
+ Rule(2L, Duration.ofSeconds(20)))), SLIDING_WIDOW_PRECISION)
SMono(rateLimiter.rateLimit(TestKey("key1"), 1)).block()
sleep(Duration.ofMillis(1100))
@@ -123,7 +128,7 @@ trait RateLimiterContract {
def shouldFailWhenLowerLimitExceeded(): Unit = {
val rateLimiter = testee().withSpecification(Rules(Seq(
Rule(2L, Duration.ofSeconds(5)),
- Rule(1L, Duration.ofSeconds(1)))))
+ Rule(1L, Duration.ofSeconds(1)))), SLIDING_WIDOW_PRECISION)
SMono(rateLimiter.rateLimit(TestKey("key1"), 1)).block()
// 2 requests in less than 1 s -> fail
@@ -135,7 +140,7 @@ trait RateLimiterContract {
def shouldSucceedWhenBothRulesAreRespected(): Unit = {
val rateLimiter = testee().withSpecification(Rules(Seq(
Rule(2L, Duration.ofSeconds(5)),
- Rule(1L, Duration.ofSeconds(1)))))
+ Rule(1L, Duration.ofSeconds(1)))), SLIDING_WIDOW_PRECISION)
SMono(rateLimiter.rateLimit(TestKey("key1"), 1)).block()
sleep(Duration.ofSeconds(1))
diff --git a/server/mailet/rate-limiter/src/test/scala/org/apache/james/rate/limiter/memory/MemoryRateLimiterTest.scala b/server/mailet/rate-limiter/src/test/scala/org/apache/james/rate/limiter/memory/MemoryRateLimiterTest.scala
index fd08d3e..313bfee 100644
--- a/server/mailet/rate-limiter/src/test/scala/org/apache/james/rate/limiter/memory/MemoryRateLimiterTest.scala
+++ b/server/mailet/rate-limiter/src/test/scala/org/apache/james/rate/limiter/memory/MemoryRateLimiterTest.scala
@@ -24,7 +24,7 @@ import java.time.Duration
import org.apache.james.rate.limiter.api.{RateLimiterContract, RateLimiterFactory}
class MemoryRateLimiterTest extends RateLimiterContract {
- override def testee(): RateLimiterFactory = new MemoryRateLimiterFactory(precision = Some(Duration.ofSeconds(1)))
+ override def testee(): RateLimiterFactory = new MemoryRateLimiterFactory()
override def sleep(duration: Duration): Unit = Thread.sleep(duration.toMillis)
}
diff --git a/server/mailet/rate-limiter/src/test/scala/org/apache/james/transport/mailets/GlobalRateLimitTest.scala b/server/mailet/rate-limiter/src/test/scala/org/apache/james/transport/mailets/GlobalRateLimitTest.scala
index 96a2b51..83af1d0 100644
--- a/server/mailet/rate-limiter/src/test/scala/org/apache/james/transport/mailets/GlobalRateLimitTest.scala
+++ b/server/mailet/rate-limiter/src/test/scala/org/apache/james/transport/mailets/GlobalRateLimitTest.scala
@@ -41,6 +41,7 @@ class GlobalRateLimitTest {
val mailet = testee(FakeMailetConfig.builder()
.mailetName("GlobalRateLimit")
.setProperty("duration", "20s")
+ .setProperty("precision", "1s")
.setProperty("count", "1")
.build())
@@ -72,6 +73,7 @@ class GlobalRateLimitTest {
val mailet = testee(FakeMailetConfig.builder()
.mailetName("GlobalRateLimit")
.setProperty("duration", "20s")
+ .setProperty("precision", "1s")
.setProperty("count", "1")
.setProperty("exceededProcessor", "tooMuchMails")
.build())
@@ -104,6 +106,7 @@ class GlobalRateLimitTest {
val mailet = testee(FakeMailetConfig.builder()
.mailetName("GlobalRateLimit")
.setProperty("duration", "20s")
+ .setProperty("precision", "1s")
.setProperty("count", "2")
.build())
@@ -144,6 +147,7 @@ class GlobalRateLimitTest {
val mailet = testee(FakeMailetConfig.builder()
.mailetName("GlobalRateLimit")
.setProperty("duration", "20s")
+ .setProperty("precision", "1s")
.setProperty("recipients", "4")
.build())
@@ -184,6 +188,7 @@ class GlobalRateLimitTest {
val mailet = testee(FakeMailetConfig.builder()
.mailetName("GlobalRateLimit")
.setProperty("duration", "20s")
+ .setProperty("precision", "1s")
.setProperty("size", "100K")
.build())
@@ -224,6 +229,7 @@ class GlobalRateLimitTest {
val mailet = testee(FakeMailetConfig.builder()
.mailetName("GlobalRateLimit")
.setProperty("duration", "20s")
+ .setProperty("precision", "1s")
.setProperty("totalSize", "1M")
.build())
@@ -267,6 +273,7 @@ class GlobalRateLimitTest {
val mailet = testee(FakeMailetConfig.builder()
.mailetName("GlobalRateLimit")
.setProperty("duration", "20s")
+ .setProperty("precision", "1s")
.setProperty("totalSize", "1G")
.build())
@@ -291,6 +298,7 @@ class GlobalRateLimitTest {
val mailet = testee(FakeMailetConfig.builder()
.mailetName("GlobalRateLimit")
.setProperty("duration", "20s")
+ .setProperty("precision", "1s")
.setProperty("count", "2")
.build())
@@ -315,6 +323,7 @@ class GlobalRateLimitTest {
val mailet = testee(FakeMailetConfig.builder()
.mailetName("GlobalRateLimit")
.setProperty("duration", "1000s")
+ .setProperty("precision", "1s")
.setProperty("size", "100K")
.setProperty("totalSize", "150K")
.setProperty("recipients", "3")
diff --git a/server/mailet/rate-limiter/src/test/scala/org/apache/james/transport/mailets/PerRecipientRateLimitTest.scala b/server/mailet/rate-limiter/src/test/scala/org/apache/james/transport/mailets/PerRecipientRateLimitTest.scala
index 66ffc54..7eb00ff 100644
--- a/server/mailet/rate-limiter/src/test/scala/org/apache/james/transport/mailets/PerRecipientRateLimitTest.scala
+++ b/server/mailet/rate-limiter/src/test/scala/org/apache/james/transport/mailets/PerRecipientRateLimitTest.scala
@@ -44,6 +44,7 @@ class PerRecipientRateLimitTest {
val mailet: PerRecipientRateLimit = testee(FakeMailetConfig.builder()
.mailetName("PerRecipientRateLimitMailet")
.setProperty("duration", "20s")
+ .setProperty("precision", "1s")
.setProperty("count", "1")
.build())
@@ -75,6 +76,7 @@ class PerRecipientRateLimitTest {
val mailet: PerRecipientRateLimit = testee(FakeMailetConfig.builder()
.mailetName("PerRecipientRateLimitMailet")
.setProperty("duration", "20s")
+ .setProperty("precision", "1s")
.setProperty("count", "1")
.build())
@@ -93,6 +95,7 @@ class PerRecipientRateLimitTest {
val mailet: PerRecipientRateLimit = testee(FakeMailetConfig.builder()
.mailetName("PerRecipientRateLimitMailet")
.setProperty("duration", "20s")
+ .setProperty("precision", "1s")
.setProperty("count", "1")
.setProperty("exceededProcessor", "tooMuchMails")
.build())
@@ -125,6 +128,7 @@ class PerRecipientRateLimitTest {
val mailet: PerRecipientRateLimit = testee(FakeMailetConfig.builder()
.mailetName("PerRecipientRateLimitMailet")
.setProperty("duration", "20s")
+ .setProperty("precision", "1s")
.setProperty("count", "1")
.setProperty("exceededProcessor", "tooMuchMails")
.build())
@@ -157,6 +161,7 @@ class PerRecipientRateLimitTest {
val mailet: PerRecipientRateLimit = testee(FakeMailetConfig.builder()
.mailetName("PerRecipientRateLimitMailet")
.setProperty("duration", "20s")
+ .setProperty("precision", "1s")
.setProperty("size", "100K")
.setProperty("exceededProcessor", "tooMuchMails")
.build())
@@ -203,6 +208,7 @@ class PerRecipientRateLimitTest {
val mailet: PerRecipientRateLimit = testee(FakeMailetConfig.builder()
.mailetName("PerRecipientRateLimitMailet")
.setProperty("duration", "20s")
+ .setProperty("precision", "1s")
.setProperty("count", "1")
.setProperty("exceededProcessor", "tooMuchMails")
.mailetContext(mailetContext)
@@ -254,6 +260,7 @@ class PerRecipientRateLimitTest {
val mailet: PerRecipientRateLimit = testee(FakeMailetConfig.builder()
.mailetName("PerRecipientRateLimitMailet")
.setProperty("duration", "20s")
+ .setProperty("precision", "1s")
.setProperty("count", "1")
.setProperty("exceededProcessor", "tooMuchMails")
.build())
@@ -287,6 +294,7 @@ class PerRecipientRateLimitTest {
val mailet: PerRecipientRateLimit = testee(FakeMailetConfig.builder()
.mailetName("PerRecipientRateLimitMailet")
.setProperty("duration", "20s")
+ .setProperty("precision", "1s")
.setProperty("count", "2")
.setProperty("size", "100K")
.setProperty("exceededProcessor", "tooMuchMails")
diff --git a/server/mailet/rate-limiter/src/test/scala/org/apache/james/transport/mailets/PerSenderRateLimitTest.scala b/server/mailet/rate-limiter/src/test/scala/org/apache/james/transport/mailets/PerSenderRateLimitTest.scala
index fcfd01c..86f6f5c 100644
--- a/server/mailet/rate-limiter/src/test/scala/org/apache/james/transport/mailets/PerSenderRateLimitTest.scala
+++ b/server/mailet/rate-limiter/src/test/scala/org/apache/james/transport/mailets/PerSenderRateLimitTest.scala
@@ -41,6 +41,7 @@ class PerSenderRateLimitTest {
val mailet = testee(FakeMailetConfig.builder()
.mailetName("PerSenderRateLimit")
.setProperty("duration", "20s")
+ .setProperty("precision", "1s")
.setProperty("count", "1")
.build())
@@ -72,6 +73,7 @@ class PerSenderRateLimitTest {
val mailet = testee(FakeMailetConfig.builder()
.mailetName("PerSenderRateLimit")
.setProperty("duration", "20s")
+ .setProperty("precision", "1s")
.setProperty("count", "1")
.setProperty("exceededProcessor", "tooMuchMails")
.build())
@@ -104,6 +106,7 @@ class PerSenderRateLimitTest {
val mailet = testee(FakeMailetConfig.builder()
.mailetName("PerSenderRateLimit")
.setProperty("duration", "20s")
+ .setProperty("precision", "1s")
.setProperty("count", "1")
.build())
@@ -135,6 +138,7 @@ class PerSenderRateLimitTest {
val mailet = testee(FakeMailetConfig.builder()
.mailetName("PerSenderRateLimit")
.setProperty("duration", "20s")
+ .setProperty("precision", "1s")
.setProperty("recipients", "4")
.build())
@@ -175,6 +179,7 @@ class PerSenderRateLimitTest {
val mailet = testee(FakeMailetConfig.builder()
.mailetName("PerSenderRateLimit")
.setProperty("duration", "20s")
+ .setProperty("precision", "1s")
.setProperty("size", "100K")
.build())
@@ -215,6 +220,7 @@ class PerSenderRateLimitTest {
val mailet = testee(FakeMailetConfig.builder()
.mailetName("PerSenderRateLimit")
.setProperty("duration", "20s")
+ .setProperty("precision", "1s")
.setProperty("totalSize", "1M")
.build())
@@ -258,6 +264,7 @@ class PerSenderRateLimitTest {
val mailet = testee(FakeMailetConfig.builder()
.mailetName("PerSenderRateLimit")
.setProperty("duration", "20s")
+ .setProperty("precision", "1s")
.setProperty("totalSize", "1G")
.build())
@@ -282,6 +289,7 @@ class PerSenderRateLimitTest {
val mailet = testee(FakeMailetConfig.builder()
.mailetName("PerSenderRateLimit")
.setProperty("duration", "20s")
+ .setProperty("precision", "1s")
.setProperty("count", "2")
.build())
@@ -306,6 +314,7 @@ class PerSenderRateLimitTest {
val mailet = testee(FakeMailetConfig.builder()
.mailetName("PerSenderRateLimit")
.setProperty("duration", "20s")
+ .setProperty("precision", "1s")
.setProperty("size", "100K")
.setProperty("recipients", "3")
.build())
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@james.apache.org
For additional commands, e-mail: notifications-help@james.apache.org