Skip to content

Commit 4ba0ea2

Browse files
Heng Cuiahassany
authored andcommitted
delete statestore if ts far-away reordered
1 parent e9b10f6 commit 4ba0ea2

15 files changed

Lines changed: 53 additions & 26 deletions

File tree

candyfloss/src/main/java/com/swisscom/daisy/cosmos/candyfloss/CandyflossKStreamsApplication.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,7 @@ public Topology buildTopology() {
221221
new CounterNormalizationProcessor(
222222
config.getPipeline(),
223223
config.getStateStoreName(),
224+
config.getStateStoreCutoffTime(),
224225
config.getMaxCounterCacheAge(),
225226
config.getIntCounterWrapAroundLimit(),
226227
config.getLongCounterWrapAroundLimit(),

candyfloss/src/main/java/com/swisscom/daisy/cosmos/candyfloss/config/JsonKStreamApplicationConfig.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ public enum InputType {
3232
private final String discardTopicName;
3333
private final String dlqTopicName;
3434
private final String stateStoreName;
35+
private final long stateStoreCutoffTime;
3536
private final long maxCounterCacheAge;
3637
private final int intCounterWrapAroundLimit;
3738
private final long longCounterWrapAroundLimit;
@@ -58,6 +59,8 @@ public static JsonKStreamApplicationConfig fromConfig(Config config)
5859
}
5960
final String discardTopicName = config.getConfig("kstream").getString("discard.topic.name");
6061
final String dlqTopicName = config.getConfig("kstream").getString("dlq.topic.name");
62+
final long stateStoreCutoffTime =
63+
config.getConfig("kstream").getLong("normalization.statestore.cutoff.time.ms");
6164
final String stateStoreName = config.getConfig("kstream").getString("state.store.name");
6265
final long maxCounterCacheAge =
6366
config.getConfig("kstream").getLong("state.store.max.counter.cache.age");
@@ -90,6 +93,7 @@ public static JsonKStreamApplicationConfig fromConfig(Config config)
9093
discardTopicName,
9194
dlqTopicName,
9295
stateStoreName,
96+
stateStoreCutoffTime,
9397
maxCounterCacheAge,
9498
intCounterWrapAroundLimit,
9599
longCounterWrapAroundLimit,

candyfloss/src/main/java/com/swisscom/daisy/cosmos/candyfloss/processors/CounterNormalizationProcessor.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ public class CounterNormalizationProcessor
4141
.description("Number of error messages that are discarded to dlq topic")
4242
.register(Metrics.globalRegistry);
4343
private final String stateStoreName;
44+
private final long stateStoreCutoffTime;
4445
private final PipelineConfig pipelineConfig;
4546
private TimestampedKeyValueStore<Bytes, Bytes> stateStore;
4647
private final long maxCounterCacheAge;
@@ -67,6 +68,7 @@ public class CounterNormalizationProcessor
6768
public CounterNormalizationProcessor(
6869
PipelineConfig pipelineConfig,
6970
String stateStoreName,
71+
long stateStoreCutoffTime,
7072
long maxCounterCacheAge,
7173
int intCounterWrapAroundLimit,
7274
long longCounterWrapAroundLimit,
@@ -75,6 +77,7 @@ public CounterNormalizationProcessor(
7577
Duration scanFrequency) {
7678
this.pipelineConfig = pipelineConfig;
7779
this.stateStoreName = stateStoreName;
80+
this.stateStoreCutoffTime = stateStoreCutoffTime;
7881
this.maxCounterCacheAge = maxCounterCacheAge;
7982
this.intCounterWrapAroundLimit = intCounterWrapAroundLimit;
8083
this.longCounterWrapAroundLimit = longCounterWrapAroundLimit;
@@ -175,10 +178,17 @@ private void normalizeCounter(
175178
}
176179
if (timestamp.toEpochMilli() < savedCounterState.timestamp()) {
177180
logger.warn(
178-
"Received a message with a timestamp {} older than saved in the counter store {}. Message: {}",
181+
"Received a message with a timestamp {} older than saved in the counter store {} "
182+
+ "(timestamp difference: {} ms). Message: {}",
179183
timestamp.toEpochMilli(),
180184
savedCounterState.timestamp(),
185+
(timestamp.toEpochMilli() - savedCounterState.timestamp()),
181186
flattenedMessage.getValue().json());
187+
188+
if (savedCounterState.timestamp() - timestamp.toEpochMilli() > stateStoreCutoffTime) {
189+
stateStore.delete(counterKey);
190+
}
191+
182192
savedCounterState = null;
183193
} else {
184194
// Save the new counterValue to the store

candyfloss/src/main/resources/application.dev.conf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ kstream {
1818
input.topic.name = dev.device-json-raw-input
1919
discard.topic.name = dev.candyfloss-processing-discard # All messages that didn't match any step in the pipeline
2020
dlq.topic.name = dev.candyfloss-processing--dlq # Messages that encountered a Java exception during the processing
21+
normalization.statestore.cutoff.time.ms = 1800000 # 30 minutes
2122
state.store.name = dev.candyfloss-counters-store # Kafka state store name to save the counter values
2223
state.store.max.counter.cache.age = 900000 // 15 minutes
2324
state.store.int.counter.wrap.limit = 10000

candyfloss/src/main/resources/application.ietf.dev.conf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ kstream {
2020
input.topic.name = daisy.dev.device-json-raw
2121
discard.topic.name = daisy.dev.candyfloss-discard
2222
dlq.topic.name = daisy.dev.candyfloss-dlq
23+
normalization.statestore.cutoff.time.ms = 1800000 # 30 minutes
2324
state.store.name = candyfloss-counters-store
2425
state.store.max.counter.cache.age = 900000 // 15 minutes
2526
state.store.int.counter.wrap.limit = 10000

candyfloss/src/main/resources/application.prod.conf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ kstream {
1818
input.topic.name = prod.device-json-raw-input
1919
discard.topic.name = prod.candyfloss-processing-discard # All messages that didn't match any step in the pipeline
2020
dlq.topic.name = prod.candyfloss-processing-dlq # Messages that encountered a Java exception during the processing
21+
normalization.statestore.cutoff.time.ms = 1800000 # 30 minutes
2122
state.store.name = prod.candyfloss-counters-store # Kafka state store name to save the counter values
2223
state.store.max.counter.cache.age = 900000 // 15 minutes
2324
state.store.int.counter.wrap.limit = 10000

candyfloss/src/main/resources/application.test.conf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ kstream {
1919
discard.topic.name = test.candyfloss-processing-discard # All messages that didn't match any step in the pipeline
2020
dlq.topic.name = test.candyfloss-processing-dlq # Messages that encountered a Java exception during the processing
2121
state.store.name = test.candyfloss-counters-store # Kafka state store name to save the counter values
22+
normalization.statestore.cutoff.time.ms = 1800000 # 30 minutes
2223
state.store.max.counter.cache.age = 900000 // 15 minutes
2324
state.store.int.counter.wrap.limit = 10000
2425
state.store.long.counter.wrap.limit = 10000000

candyfloss/src/test/java/com/swisscom/daisy/cosmos/candyfloss/processors/CounterNormalizationProcessorTest.java

Lines changed: 26 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ private Topology getTestTopology(JsonKStreamApplicationConfig appConf) {
9696
appConf.getPipeline(),
9797
appConf.getStateStoreName(),
9898
appConf.getMaxCounterCacheAge(),
99+
appConf.getStateStoreCutoffTime(),
99100
appConf.getIntCounterWrapAroundLimit(),
100101
appConf.getLongCounterWrapAroundLimit(),
101102
appConf.getCounterWrapAroundTimeMs(),
@@ -429,33 +430,33 @@ void transformCounterNegative()
429430
void transformCounterOlderMilli()
430431
throws IOException, JSONException, InvalidConfigurations, InvalidMatchConfiguration {
431432
setup("counter-normalization/application-milli.conf");
432-
var input1 =
433-
JsonUtil.readFromInputStream(
434-
getClass()
435-
.getClassLoader()
436-
.getResourceAsStream("counter-normalization/older/input1.json"));
437-
var input2 =
438-
JsonUtil.readFromInputStream(
439-
getClass()
440-
.getClassLoader()
441-
.getResourceAsStream("counter-normalization/older/input2.json"));
442-
var expected1 =
443-
JsonUtil.readFromInputStream(
444-
getClass()
445-
.getClassLoader()
446-
.getResourceAsStream("counter-normalization/older/output1.json"));
447-
var expected2 =
448-
JsonUtil.readFromInputStream(
449-
getClass()
450-
.getClassLoader()
451-
.getResourceAsStream("counter-normalization/older/output2.json"));
433+
String resourcePath = "counter-normalization/older/";
434+
List<Path> inputFiles = retrieveSortedFilenames(resourcePath, "input");
435+
List<Path> outputFiles = retrieveSortedFilenames(resourcePath, "output");
452436

453-
inputTopic.pipeInput("k1", input1);
454-
inputTopic.pipeInput("k1", input2);
437+
assertEquals(inputFiles.size(), outputFiles.size());
438+
for (var i = 0; i < inputFiles.size(); i++) {
439+
var input = inputFiles.get(i).getFileName();
440+
var inputString =
441+
JsonUtil.readFromInputStream(
442+
getClass()
443+
.getClassLoader()
444+
.getResourceAsStream(String.format("%s/%s", resourcePath, input)));
445+
446+
inputTopic.pipeInput("k1", inputString);
447+
}
455448

456449
var processed = outputTopic.readValuesToList();
457-
assertEquals(2, processed.size());
458-
JSONAssert.assertEquals(expected1, processed.get(0), true);
459-
JSONAssert.assertEquals(expected2, processed.get(1), true);
450+
assertEquals(inputFiles.size(), processed.size());
451+
for (var i = 0; i < outputFiles.size(); i++) {
452+
var output = outputFiles.get(i).getFileName();
453+
var expectedString =
454+
JsonUtil.readFromInputStream(
455+
getClass()
456+
.getClassLoader()
457+
.getResourceAsStream(String.format("%s/%s", resourcePath, output)));
458+
459+
JSONAssert.assertEquals(expectedString, processed.get(i), true);
460+
}
460461
}
461462
}

candyfloss/src/test/resources/avro-input/application.conf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ kstream {
1616
discard.topic.name = daisy.dev.avro-input-discard
1717
dlq.topic.name =daisy.dev.avro-input-dlq
1818
state.store.name = daisy.dev.avro-input-store
19+
normalization.statestore.cutoff.time.ms = 1800000 # 30 minutes
1920
state.store.max.counter.cache.age = 1000
2021
state.store.int.counter.wrap.limit = 10000
2122
state.store.long.counter.wrap.limit = 10000000

candyfloss/src/test/resources/counter-normalization/application-milli.conf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ kstream {
1313
input.topic.name = daisy.prod.device-json-raw
1414
discard.topic.name = daisy.dev.device-json-flat
1515
dlq.topic.name = daisy.dev.device-json-flat-dlq
16+
normalization.statestore.cutoff.time.ms = 1800000 # 30 minutes
1617
state.store.name = daisy.dev.device-counters-store
1718
state.store.max.counter.cache.age = 10000
1819
state.store.int.counter.wrap.limit = 10000

0 commit comments

Comments
 (0)