feat: validate shadow v3 snapshot settings
This commit is contained in:
@@ -9,6 +9,8 @@ public class ShadowObservationProperties {
|
||||
private boolean enabled;
|
||||
private String warehouseId = "";
|
||||
private int timeoutSeconds = 3;
|
||||
private int snapshotMaxAgeSeconds = 60;
|
||||
private int quietIntervalMillis = 1000;
|
||||
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
@@ -33,4 +35,20 @@ public class ShadowObservationProperties {
|
||||
public void setTimeoutSeconds(int timeoutSeconds) {
|
||||
this.timeoutSeconds = timeoutSeconds;
|
||||
}
|
||||
|
||||
public int getSnapshotMaxAgeSeconds() {
|
||||
return snapshotMaxAgeSeconds;
|
||||
}
|
||||
|
||||
public void setSnapshotMaxAgeSeconds(int snapshotMaxAgeSeconds) {
|
||||
this.snapshotMaxAgeSeconds = snapshotMaxAgeSeconds;
|
||||
}
|
||||
|
||||
public int getQuietIntervalMillis() {
|
||||
return quietIntervalMillis;
|
||||
}
|
||||
|
||||
public void setQuietIntervalMillis(int quietIntervalMillis) {
|
||||
this.quietIntervalMillis = quietIntervalMillis;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,8 +33,16 @@ public class ShadowSafetyGuard implements InitializingBean {
|
||||
if (!algorithmProperties.isDatabaseWritesEnabled()) {
|
||||
throw new IllegalStateException("Shadow observation requires algorithm database writes for alg.* read models");
|
||||
}
|
||||
if (shadowProperties.getTimeoutSeconds() <= 0) {
|
||||
throw new IllegalStateException("Shadow observation timeout must be positive");
|
||||
if (shadowProperties.getTimeoutSeconds() < 1 || shadowProperties.getTimeoutSeconds() > 30) {
|
||||
throw new IllegalStateException("Shadow observation timeout must be between 1 and 30 seconds");
|
||||
}
|
||||
if (shadowProperties.getSnapshotMaxAgeSeconds() < 5
|
||||
|| shadowProperties.getSnapshotMaxAgeSeconds() > 300) {
|
||||
throw new IllegalStateException("Shadow snapshot maximum age must be between 5 and 300 seconds");
|
||||
}
|
||||
if (shadowProperties.getQuietIntervalMillis() < 100
|
||||
|| shadowProperties.getQuietIntervalMillis() > 10000) {
|
||||
throw new IllegalStateException("Shadow quiet interval must be between 100 and 10000 milliseconds");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.ruoyi.algorithm.shadow;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
final class WarehouseIdNormalizer {
|
||||
static boolean equivalent(String first, String second) {
|
||||
if (first == null || second == null) {
|
||||
return false;
|
||||
}
|
||||
String left = first.trim();
|
||||
String right = second.trim();
|
||||
if (left.matches("[0-9]+") && right.matches("[0-9]+")) {
|
||||
return new BigInteger(left).equals(new BigInteger(right));
|
||||
}
|
||||
return left.equals(right);
|
||||
}
|
||||
|
||||
private WarehouseIdNormalizer() { }
|
||||
}
|
||||
@@ -185,6 +185,8 @@ fortucky:
|
||||
enabled: ${FORTUCKY_SHADOW_ENABLED:false}
|
||||
warehouse-id: ${FORTUCKY_SHADOW_WAREHOUSE_ID:}
|
||||
timeout-seconds: ${FORTUCKY_SHADOW_TIMEOUT_SECONDS:3}
|
||||
snapshot-max-age-seconds: ${FORTUCKY_SHADOW_SNAPSHOT_MAX_AGE_SECONDS:60}
|
||||
quiet-interval-millis: ${FORTUCKY_SHADOW_QUIET_INTERVAL_MILLIS:1000}
|
||||
algorithm:
|
||||
mode: ${FORTUCKY_ALGORITHM_MODE:SHADOW}
|
||||
warehouse-id: ${FORTUCKY_ALGORITHM_WAREHOUSE_ID:01}
|
||||
|
||||
@@ -33,6 +33,8 @@ class ShadowConfigurationTest {
|
||||
assertThat(shadow.isEnabled()).isFalse();
|
||||
assertThat(shadow.getWarehouseId()).isEmpty();
|
||||
assertThat(shadow.getTimeoutSeconds()).isEqualTo(3);
|
||||
assertThat(shadow.getSnapshotMaxAgeSeconds()).isEqualTo(60);
|
||||
assertThat(shadow.getQuietIntervalMillis()).isEqualTo(1000);
|
||||
assertThat(algorithm.getMode()).isEqualTo(SchedulingMode.SHADOW);
|
||||
assertThat(algorithm.isDatabaseWritesEnabled()).isTrue();
|
||||
assertThat(algorithm.getWarehouseId()).isEqualTo("01");
|
||||
|
||||
@@ -59,6 +59,23 @@ class ShadowSafetyGuardTest {
|
||||
.doesNotThrowAnyException();
|
||||
}
|
||||
|
||||
@Test
|
||||
void rejectsSnapshotAndQuietIntervalOutsideValidatedRanges() {
|
||||
ShadowObservationProperties shadow = enabledShadow();
|
||||
AlgorithmProperties algorithm = new AlgorithmProperties();
|
||||
algorithm.setMode(SchedulingMode.SHADOW);
|
||||
algorithm.setDatabaseWritesEnabled(true);
|
||||
|
||||
shadow.setSnapshotMaxAgeSeconds(4);
|
||||
assertThatThrownBy(() -> new ShadowSafetyGuard(shadow, algorithm).validate())
|
||||
.hasMessageContaining("between 5 and 300");
|
||||
|
||||
shadow.setSnapshotMaxAgeSeconds(60);
|
||||
shadow.setQuietIntervalMillis(10001);
|
||||
assertThatThrownBy(() -> new ShadowSafetyGuard(shadow, algorithm).validate())
|
||||
.hasMessageContaining("between 100 and 10000");
|
||||
}
|
||||
|
||||
private ShadowObservationProperties enabledShadow() {
|
||||
ShadowObservationProperties properties = new ShadowObservationProperties();
|
||||
properties.setEnabled(true);
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.ruoyi.algorithm.shadow;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class WarehouseIdNormalizerTest {
|
||||
@Test
|
||||
void comparesNumericIdsByValueAndOtherIdsAfterTrimming() {
|
||||
assertThat(WarehouseIdNormalizer.equivalent("1", "01")).isTrue();
|
||||
assertThat(WarehouseIdNormalizer.equivalent(" 01 ", "1")).isTrue();
|
||||
assertThat(WarehouseIdNormalizer.equivalent("W02", "01")).isFalse();
|
||||
assertThat(WarehouseIdNormalizer.equivalent(" W02 ", "W02")).isTrue();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user