Skip to content

Commit ea123e7

Browse files
committed
rate limiter
Signed-off-by: Attila Mészáros <a_meszaros@apple.com>
1 parent 2179ca0 commit ea123e7

File tree

2 files changed

+67
-2
lines changed

2 files changed

+67
-2
lines changed

operator-framework/src/main/java/io/javaoperatorsdk/operator/config/loader/ConfigLoader.java

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import io.javaoperatorsdk.operator.config.loader.provider.AgregatePrirityListConfigProvider;
3131
import io.javaoperatorsdk.operator.config.loader.provider.EnvVarConfigProvider;
3232
import io.javaoperatorsdk.operator.config.loader.provider.SystemPropertyConfigProvider;
33+
import io.javaoperatorsdk.operator.processing.event.rate.LinearRateLimiter;
3334
import io.javaoperatorsdk.operator.processing.retry.GenericRetry;
3435

3536
public class ConfigLoader {
@@ -121,6 +122,12 @@ public static ConfigLoader getDefault() {
121122
static final String RETRY_INTERVAL_MULTIPLIER_SUFFIX = "retry.interval-multiplier";
122123
static final String RETRY_MAX_INTERVAL_SUFFIX = "retry.max-interval";
123124

125+
// ---------------------------------------------------------------------------
126+
// Controller-level rate-limiter property suffixes
127+
// ---------------------------------------------------------------------------
128+
static final String RATE_LIMITER_REFRESH_PERIOD_SUFFIX = "rate-limiter.refresh-period";
129+
static final String RATE_LIMITER_LIMIT_FOR_PERIOD_SUFFIX = "rate-limiter.limit-for-period";
130+
124131
// ---------------------------------------------------------------------------
125132
// Controller-level (ControllerConfigurationOverrider) bindings
126133
// The key used at runtime is built as:
@@ -147,7 +154,11 @@ public static ConfigLoader getDefault() {
147154
Boolean.class,
148155
ControllerConfigurationOverrider::withTriggerReconcilerOnAllEvents),
149156
new ConfigBinding<>(
150-
"informer-list-limit",
157+
"informer.label-selector",
158+
String.class,
159+
ControllerConfigurationOverrider::withLabelSelector),
160+
new ConfigBinding<>(
161+
"informer.list-limit",
151162
Long.class,
152163
ControllerConfigurationOverrider::withInformerListLimit));
153164

@@ -210,6 +221,11 @@ Consumer<ControllerConfigurationOverrider<R>> applyControllerConfigs(String cont
210221
if (retryStep != null) {
211222
consumer = consumer == null ? retryStep : consumer.andThen(retryStep);
212223
}
224+
Consumer<ControllerConfigurationOverrider<R>> rateLimiterStep =
225+
buildRateLimiterConsumer(prefix);
226+
if (rateLimiterStep != null) {
227+
consumer = consumer.andThen(rateLimiterStep);
228+
}
213229
return consumer;
214230
}
215231

@@ -246,6 +262,32 @@ private <R extends HasMetadata> Consumer<ControllerConfigurationOverrider<R>> bu
246262
};
247263
}
248264

265+
/**
266+
* Returns a {@link Consumer} that builds a {@link LinearRateLimiter} only if {@code
267+
* rate-limiter.limit-for-period} is present and positive (a non-positive value would deactivate
268+
* the limiter and is therefore treated as absent). {@code rate-limiter.refresh-period} is applied
269+
* when also present; otherwise the default refresh period is used. Returns {@code null} when no
270+
* effective rate-limiter configuration is found.
271+
*/
272+
private <R extends HasMetadata>
273+
Consumer<ControllerConfigurationOverrider<R>> buildRateLimiterConsumer(String prefix) {
274+
Optional<Duration> refreshPeriod =
275+
configProvider.getValue(prefix + RATE_LIMITER_REFRESH_PERIOD_SUFFIX, Duration.class);
276+
Optional<Integer> limitForPeriod =
277+
configProvider.getValue(prefix + RATE_LIMITER_LIMIT_FOR_PERIOD_SUFFIX, Integer.class);
278+
279+
if (limitForPeriod.isEmpty() || limitForPeriod.get() <= 0) {
280+
return null;
281+
}
282+
283+
return overrider -> {
284+
var rateLimiter =
285+
new LinearRateLimiter(
286+
refreshPeriod.orElse(LinearRateLimiter.DEFAULT_REFRESH_PERIOD), limitForPeriod.get());
287+
overrider.withRateLimiter(rateLimiter);
288+
};
289+
}
290+
249291
/**
250292
* If leader election is explicitly disabled via {@code leader-election.enabled=false}, returns
251293
* {@code null}. Otherwise, if at least one leader-election property is present (with {@code

operator-framework/src/test/java/io/javaoperatorsdk/operator/config/loader/ConfigLoaderTest.java

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,10 @@ public <T> Optional<T> getValue(String key, Class<T> type) {
201201
"josdk.controller.ctrl.max-reconciliation-interval",
202202
"josdk.controller.ctrl.field-manager",
203203
"josdk.controller.ctrl.trigger-reconciler-on-all-events",
204-
"josdk.controller.ctrl.informer-list-limit");
204+
"josdk.controller.ctrl.informer.label-selector",
205+
"josdk.controller.ctrl.informer.list-limit",
206+
"josdk.controller.ctrl.rate-limiter.refresh-period",
207+
"josdk.controller.ctrl.rate-limiter.limit-for-period");
205208
}
206209

207210
@Test
@@ -214,6 +217,26 @@ void controllerKeyPrefixIsJosdkControllerDot() {
214217
assertThat(ConfigLoader.DEFAULT_CONTROLLER_KEY_PREFIX).isEqualTo("josdk.controller.");
215218
}
216219

220+
// -- rate limiter -----------------------------------------------------------
221+
222+
@Test
223+
void rateLimiterQueriesExpectedKeys() {
224+
var queriedKeys = new ArrayList<String>();
225+
ConfigProvider recordingProvider =
226+
new ConfigProvider() {
227+
@Override
228+
public <T> Optional<T> getValue(String key, Class<T> type) {
229+
queriedKeys.add(key);
230+
return Optional.empty();
231+
}
232+
};
233+
new ConfigLoader(recordingProvider).applyControllerConfigs("ctrl");
234+
assertThat(queriedKeys)
235+
.contains(
236+
"josdk.controller.ctrl.rate-limiter.refresh-period",
237+
"josdk.controller.ctrl.rate-limiter.limit-for-period");
238+
}
239+
217240
// -- binding coverage -------------------------------------------------------
218241

219242
/**

0 commit comments

Comments
 (0)