Skip to content

Commit

Permalink
Merge pull request #81 from quarkiverse/runtime_config
Browse files Browse the repository at this point in the history
allow runtime bucket configuration
  • Loading branch information
rmanibus authored Dec 16, 2023
2 parents 859175b + 762e578 commit 6fff32f
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 83 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -127,20 +127,20 @@ private void visit(Map<MethodDescription, RateLimitCheckBuildItem> visited, Anno
}

@BuildStep
@Record(ExecutionTime.STATIC_INIT)
@Record(ExecutionTime.RUNTIME_INIT)
void createBucketPodStorage(
BucketPodStorageRecorder recorder,
List<RateLimitCheckBuildItem> rateLimitChecks,
BuildProducer<SyntheticBeanBuildItem> syntheticBeans) {

rateLimitChecks.forEach(
item -> recorder.registerMethod(item.getMethodDescription(), item.getBucket(), item.getIdentityResolver()));

syntheticBeans.produce(
SyntheticBeanBuildItem.configure(BucketPodStorage.class)
.scope(ApplicationScoped.class)
.unremovable()
.runtimeValue(recorder.create())
.runtimeProxy(recorder.create())
.setRuntimeInit()
.done());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,29 +7,29 @@
import io.github.bucket4j.Bandwidth;
import io.github.bucket4j.BucketConfiguration;
import io.github.bucket4j.ConfigurationBuilder;
import io.quarkiverse.bucket4j.runtime.RateLimiterRuntimeConfig.Bucket;
import io.quarkiverse.bucket4j.runtime.RateLimiterRuntimeConfig.Limit;
import io.quarkiverse.bucket4j.runtime.resolver.IdentityResolver;
import io.quarkus.runtime.RuntimeValue;
import io.quarkus.runtime.annotations.Recorder;

@Recorder
public class BucketPodStorageRecorder {

private final RateLimiterConfig config;
private final RateLimiterRuntimeConfig config;
Map<MethodDescription, BucketPod> pods = new HashMap<>();

public BucketPodStorageRecorder(RateLimiterConfig config) {
public BucketPodStorageRecorder(RateLimiterRuntimeConfig config) {
this.config = config;
}

private BucketPod getBucketPod(MethodDescription methodDescription, String key,
String identityResolverClassName) {
RateLimiterConfig.Bucket bucketConfig = config.buckets().get(key);
Bucket bucketConfig = config.buckets().get(key);
if (bucketConfig == null) {
throw new IllegalStateException("missing limits config for " + key);
}

ConfigurationBuilder builder = BucketConfiguration.builder();
for (RateLimiterConfig.Limit limit : bucketConfig.limits()) {
for (Limit limit : bucketConfig.limits()) {
builder.addLimit(Bandwidth.builder()
.capacity(limit.permittedUses())
.refillGreedy(limit.permittedUses(), limit.period())
Expand All @@ -51,7 +51,7 @@ public void registerMethod(MethodDescription description,
pods.put(description, getBucketPod(description, key, identityResolverClassName));
}

public RuntimeValue<BucketPodStorage> create() {
return new RuntimeValue<>(methodDescription -> pods.get(methodDescription));
public BucketPodStorage create() {
return methodDescription -> pods.get(methodDescription);
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
package io.quarkiverse.bucket4j.runtime;

import java.time.Duration;
import java.util.List;
import java.util.Map;

import io.quarkus.runtime.annotations.ConfigDocMapKey;
import io.quarkus.runtime.annotations.ConfigGroup;
import io.quarkus.runtime.annotations.ConfigPhase;
import io.quarkus.runtime.annotations.ConfigRoot;
import io.quarkus.runtime.configuration.DurationConverter;
Expand Down Expand Up @@ -32,4 +36,55 @@ public interface RateLimiterRuntimeConfig {
@WithConverter(DurationConverter.class)
Duration keepAfterRefill();

/**
* Represents a group of limits applied to a method
* identified by the bucket id
*/
@ConfigDocMapKey("bucket-id")
Map<String, Bucket> buckets();

/**
* represent one single bucket
*/
@ConfigGroup
interface Bucket {

/**
* Identity resolver allow to segment the population.
* Each resolved identity key will have its own quota.
* this must be a valid CDI bean implementing IdentityResolver.
*/
@WithDefault("io.quarkiverse.bucket4j.runtime.resolver.ConstantResolver")
String identityResolver();

/**
* Limits enforced for this bucket
*/
List<Limit> limits();

/**
* If true, permitted uses are shared for all methods using the same bucket id.
* If false, each method has its own quota.
*/
@WithDefault("false")
Boolean shared();
}

/**
* represent one single limit
*/
@ConfigGroup
interface Limit {

/**
* Number of usage per period
*/
int permittedUses();

/**
* Evaluation period
*/
@WithConverter(DurationConverter.class)
Duration period();
}
}

0 comments on commit 6fff32f

Please sign in to comment.