Search in sources :

Example 1 with RequestLimitRule

use of es.moki.ratelimitj.core.limiter.request.RequestLimitRule in project ratelimitj by mokies.

the class InMemorySlidingWindowRequestRateLimiter method eqOrGeLimit.

private boolean eqOrGeLimit(String key, int weight, boolean strictlyGreater) {
    requireNonNull(key, "key cannot be null");
    requireNonNull(rules, "rules cannot be null");
    if (rules.isEmpty()) {
        throw new IllegalArgumentException("at least one rule must be provided");
    }
    final long now = timeSupplier.get();
    // TODO implement cleanup
    final int longestDurationSeconds = rules.stream().map(RequestLimitRule::getDurationSeconds).reduce(Integer::max).orElse(0);
    List<SavedKey> savedKeys = new ArrayList<>(rules.size());
    Map<String, Long> keyMap = getMap(key, longestDurationSeconds);
    boolean geLimit = false;
    // TODO perform each rule calculation in parallel
    for (RequestLimitRule rule : rules) {
        SavedKey savedKey = new SavedKey(now, rule.getDurationSeconds(), rule.getPrecision());
        savedKeys.add(savedKey);
        Long oldTs = keyMap.get(savedKey.tsKey);
        oldTs = oldTs != null ? oldTs : savedKey.trimBefore;
        if (oldTs > now) {
            // don't write in the past
            return true;
        }
        // discover what needs to be cleaned up
        long decr = 0;
        List<String> dele = new ArrayList<>();
        long trim = Math.min(savedKey.trimBefore, oldTs + savedKey.blocks);
        for (long oldBlock = oldTs; oldBlock == trim - 1; oldBlock++) {
            String bkey = savedKey.countKey + oldBlock;
            Long bcount = keyMap.get(bkey);
            if (bcount != null) {
                decr = decr + bcount;
                dele.add(bkey);
            }
        }
        // handle cleanup
        Long cur;
        if (!dele.isEmpty()) {
            dele.forEach(keyMap::remove);
            final long decrement = decr;
            cur = keyMap.compute(savedKey.countKey, (k, v) -> v - decrement);
        } else {
            cur = keyMap.get(savedKey.countKey);
        }
        // check our limits
        long count = coalesce(cur, 0L) + weight;
        if (count > rule.getLimit()) {
            // over limit, don't record request
            return true;
        } else if (!strictlyGreater && count == rule.getLimit()) {
            // at limit, do record request
            geLimit = true;
        }
    }
    // there is enough resources, update the counts
    if (weight != 0) {
        for (SavedKey savedKey : savedKeys) {
            // update the current timestamp, count, and bucket count
            keyMap.put(savedKey.tsKey, savedKey.trimBefore);
            Long computedCountKeyValue = keyMap.compute(savedKey.countKey, (k, v) -> coalesce(v, 0L) + weight);
            Long computedCountKeyBlockIdValue = keyMap.compute(savedKey.countKey + savedKey.blockId, (k, v) -> coalesce(v, 0L) + weight);
            if (LOG.isDebugEnabled()) {
                LOG.debug("{} {}={}", key, savedKey.countKey, computedCountKeyValue);
                LOG.debug("{} {}={}", key, savedKey.countKey + savedKey.blockId, computedCountKeyBlockIdValue);
            }
        }
    }
    return geLimit;
}
Also used : Logger(org.slf4j.Logger) KeyLockManagers(de.jkeylockmanager.manager.KeyLockManagers) ExpiringMap(net.jodah.expiringmap.ExpiringMap) LoggerFactory(org.slf4j.LoggerFactory) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) Set(java.util.Set) ThreadSafe(javax.annotation.concurrent.ThreadSafe) SystemTimeSupplier(es.moki.ratelimitj.core.time.SystemTimeSupplier) ArrayList(java.util.ArrayList) ConcurrentMap(java.util.concurrent.ConcurrentMap) TimeUnit(java.util.concurrent.TimeUnit) List(java.util.List) RequestRateLimiter(es.moki.ratelimitj.core.limiter.request.RequestRateLimiter) TimeSupplier(es.moki.ratelimitj.core.time.TimeSupplier) RequestLimitRule(es.moki.ratelimitj.core.limiter.request.RequestLimitRule) Map(java.util.Map) Objects.requireNonNull(java.util.Objects.requireNonNull) KeyLockManager(de.jkeylockmanager.manager.KeyLockManager) ExpirationPolicy(net.jodah.expiringmap.ExpirationPolicy) RateLimitUtils.coalesce(es.moki.ratelimitj.core.RateLimitUtils.coalesce) ArrayList(java.util.ArrayList) RequestLimitRule(es.moki.ratelimitj.core.limiter.request.RequestLimitRule)

Example 2 with RequestLimitRule

use of es.moki.ratelimitj.core.limiter.request.RequestLimitRule in project ratelimitj by mokies.

the class InMemoryRateLimiterFactoryTest method shouldReturnTheSameInstanceForSameSetOfRules.

@Test
void shouldReturnTheSameInstanceForSameSetOfRules() {
    RequestLimitRule rule1a = RequestLimitRule.of(1, TimeUnit.MINUTES, 10);
    RequestLimitRule rule1b = RequestLimitRule.of(1, TimeUnit.HOURS, 100);
    RequestRateLimiter rateLimiter1 = factory.getInstance(ImmutableSet.of(rule1a, rule1b));
    RequestLimitRule rule2a = RequestLimitRule.of(1, TimeUnit.MINUTES, 10);
    RequestLimitRule rule2b = RequestLimitRule.of(1, TimeUnit.HOURS, 100);
    RequestRateLimiter rateLimiter2 = factory.getInstance(ImmutableSet.of(rule2a, rule2b));
    assertThat(rateLimiter1).isSameAs(rateLimiter2);
}
Also used : RequestRateLimiter(es.moki.ratelimitj.core.limiter.request.RequestRateLimiter) RequestLimitRule(es.moki.ratelimitj.core.limiter.request.RequestLimitRule) Test(org.junit.jupiter.api.Test)

Example 3 with RequestLimitRule

use of es.moki.ratelimitj.core.limiter.request.RequestLimitRule in project ratelimitj by mokies.

the class AbstractAsyncRequestRateLimiterTest method shouldLimitSingleWindowAsync.

@Test
void shouldLimitSingleWindowAsync() throws Exception {
    ImmutableSet<RequestLimitRule> rules = ImmutableSet.of(RequestLimitRule.of(10, TimeUnit.SECONDS, 5));
    AsyncRequestRateLimiter rateLimiter = getAsyncRateLimiter(rules, timeBandit);
    Queue<CompletionStage> stageAsserts = new ConcurrentLinkedQueue<>();
    Stream.generate(() -> "ip:127.0.0.2").limit(5).forEach(key -> {
        timeBandit.addUnixTimeMilliSeconds(1000L);
        stageAsserts.add(rateLimiter.overLimitAsync(key).thenAccept(result -> assertThat(result).isFalse()));
    });
    for (CompletionStage stage : stageAsserts) {
        stage.toCompletableFuture().get();
    }
    assertThat(rateLimiter.overLimitAsync("ip:127.0.0.2").toCompletableFuture().get()).isTrue();
}
Also used : AsyncRequestRateLimiter(es.moki.ratelimitj.core.limiter.request.AsyncRequestRateLimiter) ImmutableSet(com.google.common.collect.ImmutableSet) Logger(org.slf4j.Logger) Assertions.assertThat(org.assertj.core.api.Assertions.assertThat) LoggerFactory(org.slf4j.LoggerFactory) Set(java.util.Set) Test(org.junit.jupiter.api.Test) TimeUnit(java.util.concurrent.TimeUnit) CompletionStage(java.util.concurrent.CompletionStage) Stream(java.util.stream.Stream) TimeSupplier(es.moki.ratelimitj.core.time.TimeSupplier) RequestLimitRule(es.moki.ratelimitj.core.limiter.request.RequestLimitRule) Queue(java.util.Queue) TimeBanditSupplier(es.moki.ratelimitj.test.time.TimeBanditSupplier) ConcurrentLinkedQueue(java.util.concurrent.ConcurrentLinkedQueue) AsyncRequestRateLimiter(es.moki.ratelimitj.core.limiter.request.AsyncRequestRateLimiter) ConcurrentLinkedQueue(java.util.concurrent.ConcurrentLinkedQueue) RequestLimitRule(es.moki.ratelimitj.core.limiter.request.RequestLimitRule) CompletionStage(java.util.concurrent.CompletionStage) Test(org.junit.jupiter.api.Test)

Example 4 with RequestLimitRule

use of es.moki.ratelimitj.core.limiter.request.RequestLimitRule in project ratelimitj by mokies.

the class AbstractReactiveRequestRateLimiterTest method shouldLimitSingleWindowReactive.

@Test
void shouldLimitSingleWindowReactive() {
    ImmutableSet<RequestLimitRule> rules = ImmutableSet.of(RequestLimitRule.of(10, TimeUnit.SECONDS, 5));
    ReactiveRequestRateLimiter rateLimiter = getRateLimiter(rules, timeBandit);
    Flux<Boolean> overLimitFlux = Flux.just("ip:127.0.1.5").repeat(5).flatMap(key -> {
        timeBandit.addUnixTimeMilliSeconds(100);
        return rateLimiter.overLimitWhenIncrementedReactive(key);
    });
    overLimitFlux.toStream().forEach(result -> assertThat(result).isFalse());
    assertThat(rateLimiter.overLimitWhenIncrementedReactive("ip:127.0.1.5").block()).isTrue();
}
Also used : ReactiveRequestRateLimiter(es.moki.ratelimitj.core.limiter.request.ReactiveRequestRateLimiter) RequestLimitRule(es.moki.ratelimitj.core.limiter.request.RequestLimitRule) Test(org.junit.jupiter.api.Test)

Example 5 with RequestLimitRule

use of es.moki.ratelimitj.core.limiter.request.RequestLimitRule in project ratelimitj by mokies.

the class AbstractReactiveRequestRateLimiterTest method shouldResetLimit.

@Test
void shouldResetLimit() {
    ImmutableSet<RequestLimitRule> rules = ImmutableSet.of(RequestLimitRule.of(60, TimeUnit.SECONDS, 1));
    ReactiveRequestRateLimiter rateLimiter = getRateLimiter(rules, timeBandit);
    String key = "ip:127.1.0.1";
    assertThat(rateLimiter.overLimitWhenIncrementedReactive(key).block()).isFalse();
    assertThat(rateLimiter.overLimitWhenIncrementedReactive(key).block()).isTrue();
    assertThat(rateLimiter.resetLimitReactive(key).block()).isTrue();
    assertThat(rateLimiter.resetLimitReactive(key).block()).isFalse();
    assertThat(rateLimiter.overLimitWhenIncrementedReactive(key).block()).isFalse();
}
Also used : ReactiveRequestRateLimiter(es.moki.ratelimitj.core.limiter.request.ReactiveRequestRateLimiter) RequestLimitRule(es.moki.ratelimitj.core.limiter.request.RequestLimitRule) Test(org.junit.jupiter.api.Test)

Aggregations

RequestLimitRule (es.moki.ratelimitj.core.limiter.request.RequestLimitRule)23 Test (org.junit.jupiter.api.Test)21 RequestRateLimiter (es.moki.ratelimitj.core.limiter.request.RequestRateLimiter)16 TimeSupplier (es.moki.ratelimitj.core.time.TimeSupplier)5 Set (java.util.Set)5 Logger (org.slf4j.Logger)5 LoggerFactory (org.slf4j.LoggerFactory)5 ReactiveRequestRateLimiter (es.moki.ratelimitj.core.limiter.request.ReactiveRequestRateLimiter)4 TimeUnit (java.util.concurrent.TimeUnit)4 ImmutableSet (com.google.common.collect.ImmutableSet)3 AsyncRequestRateLimiter (es.moki.ratelimitj.core.limiter.request.AsyncRequestRateLimiter)3 TimeBanditSupplier (es.moki.ratelimitj.test.time.TimeBanditSupplier)3 RateLimitUtils.coalesce (es.moki.ratelimitj.core.RateLimitUtils.coalesce)2 SystemTimeSupplier (es.moki.ratelimitj.core.time.SystemTimeSupplier)2 ArrayList (java.util.ArrayList)2 List (java.util.List)2 Objects.requireNonNull (java.util.Objects.requireNonNull)2 Queue (java.util.Queue)2 CompletionStage (java.util.concurrent.CompletionStage)2 ConcurrentLinkedQueue (java.util.concurrent.ConcurrentLinkedQueue)2