Browse Source

Alarm rules: no-data filter predicate

pull/14440/head
Viacheslav Klimov 10 months ago
parent
commit
615f9d284c
  1. 2
      application/src/main/java/org/thingsboard/server/actors/calculatedField/CalculatedFieldManagerMessageProcessor.java
  2. 5
      application/src/main/java/org/thingsboard/server/service/cf/ctx/state/CalculatedFieldCtx.java
  3. 12
      application/src/main/java/org/thingsboard/server/service/cf/ctx/state/alarm/AlarmCalculatedFieldState.java
  4. 2
      common/data/src/main/java/org/thingsboard/server/common/data/alarm/rule/AlarmRule.java
  5. 5
      common/data/src/main/java/org/thingsboard/server/common/data/alarm/rule/condition/AlarmCondition.java
  6. 5
      common/data/src/main/java/org/thingsboard/server/common/data/alarm/rule/condition/expression/AlarmConditionExpression.java
  7. 19
      common/data/src/main/java/org/thingsboard/server/common/data/alarm/rule/condition/expression/AlarmConditionFilter.java
  8. 6
      common/data/src/main/java/org/thingsboard/server/common/data/alarm/rule/condition/expression/SimpleAlarmConditionExpression.java
  9. 1
      common/data/src/main/java/org/thingsboard/server/common/data/alarm/rule/condition/expression/predicate/FilterPredicateType.java
  10. 4
      common/data/src/main/java/org/thingsboard/server/common/data/alarm/rule/condition/expression/predicate/KeyFilterPredicate.java
  11. 39
      common/data/src/main/java/org/thingsboard/server/common/data/alarm/rule/condition/expression/predicate/NoDataFilterPredicate.java

2
application/src/main/java/org/thingsboard/server/actors/calculatedField/CalculatedFieldManagerMessageProcessor.java

@ -179,7 +179,7 @@ public class CalculatedFieldManagerMessageProcessor extends AbstractContextAware
cfsReevaluationTask = systemContext.getScheduler().scheduleWithFixedDelay(() -> {
try {
calculatedFields.values().forEach(cf -> {
if (cf.isRequiresScheduledReevaluation()) {
if (cf.requiresScheduledReevaluation()) {
applyToTargetCfEntityActors(cf, TbCallback.EMPTY, (entityId, callback) -> {
log.debug("[{}][{}] Pushing scheduled CF reevaluate msg", entityId, cf.getCfId());
getOrCreateActor(entityId).tell(new CalculatedFieldReevaluateMsg(tenantId, cf));

5
application/src/main/java/org/thingsboard/server/service/cf/ctx/state/CalculatedFieldCtx.java

@ -210,7 +210,7 @@ public class CalculatedFieldCtx implements Closeable {
this.maxSingleValueArgumentSize = systemContext.getApiLimitService().getLimit(tenantId, DefaultTenantProfileConfiguration::getMaxSingleValueArgumentSizeInKBytes) * 1024;
}
public boolean isRequiresScheduledReevaluation() {
public boolean requiresScheduledReevaluation() {
long now = System.currentTimeMillis();
if (calculatedField.getConfiguration() instanceof EntityAggregationCalculatedFieldConfiguration entityAggregationConfig) {
Watermark watermark = entityAggregationConfig.getWatermark();
@ -230,8 +230,9 @@ public class CalculatedFieldCtx implements Closeable {
}
boolean requiresScheduledReevaluation = calculatedField.getConfiguration().requiresScheduledReevaluation();
if (calculatedField.getConfiguration() instanceof AlarmCalculatedFieldConfiguration) {
long reevaluationIntervalMillis = TimeUnit.SECONDS.toMillis(systemContext.getAlarmRulesReevaluationInterval());
// TODO: handle reeaval for no-data conditions!
if (requiresScheduledReevaluation) {
long reevaluationIntervalMillis = TimeUnit.SECONDS.toMillis(systemContext.getAlarmRulesReevaluationInterval());
if (now - lastReevaluationTs >= reevaluationIntervalMillis) {
lastReevaluationTs = now;
return true;

12
application/src/main/java/org/thingsboard/server/service/cf/ctx/state/alarm/AlarmCalculatedFieldState.java

@ -46,6 +46,7 @@ import org.thingsboard.server.common.data.alarm.rule.condition.expression.TbelAl
import org.thingsboard.server.common.data.alarm.rule.condition.expression.predicate.BooleanFilterPredicate;
import org.thingsboard.server.common.data.alarm.rule.condition.expression.predicate.ComplexFilterPredicate;
import org.thingsboard.server.common.data.alarm.rule.condition.expression.predicate.KeyFilterPredicate;
import org.thingsboard.server.common.data.alarm.rule.condition.expression.predicate.NoDataFilterPredicate;
import org.thingsboard.server.common.data.alarm.rule.condition.expression.predicate.NumericFilterPredicate;
import org.thingsboard.server.common.data.alarm.rule.condition.expression.predicate.StringFilterPredicate;
import org.thingsboard.server.common.data.audit.ActionType;
@ -428,6 +429,7 @@ public class AlarmCalculatedFieldState extends BaseCalculatedFieldState {
case STRING -> evalStrPredicate(argument, (StringFilterPredicate) predicate);
case NUMERIC -> evalNumPredicate(argument, (NumericFilterPredicate) predicate);
case BOOLEAN -> evalBooleanPredicate(argument, (BooleanFilterPredicate) predicate);
case NO_DATA -> evalNoDataPredicate(argument, (NoDataFilterPredicate) predicate);
case COMPLEX -> evalComplexPredicate(argument, (ComplexFilterPredicate) predicate);
};
}
@ -512,6 +514,16 @@ public class AlarmCalculatedFieldState extends BaseCalculatedFieldState {
};
}
private boolean evalNoDataPredicate(SingleValueArgumentEntry argument, NoDataFilterPredicate predicate) {
long passedMs = System.currentTimeMillis() - argument.getTs();
long duration = resolveValue(predicate.getDuration(), KvUtil::getLongValue);
if (duration > 0) {
return passedMs >= predicate.getUnit().toMillis(duration);
} else {
return false;
}
}
protected <T> T resolveValue(AlarmConditionValue<T> conditionValue, Function<KvEntry, T> mapper) {
T value = conditionValue.getStaticValue();
if (value == null) {

2
common/data/src/main/java/org/thingsboard/server/common/data/alarm/rule/AlarmRule.java

@ -33,7 +33,7 @@ public class AlarmRule {
@JsonIgnore
public boolean requiresScheduledReevaluation() {
return condition.hasSchedule();
return condition.requiresScheduledReevaluation();
}
}

5
common/data/src/main/java/org/thingsboard/server/common/data/alarm/rule/condition/AlarmCondition.java

@ -50,6 +50,11 @@ public abstract class AlarmCondition {
return schedule != null && !(schedule.getStaticValue() instanceof AnyTimeSchedule);
}
@JsonIgnore
public boolean requiresScheduledReevaluation() {
return hasSchedule() || expression.requiresScheduledReevaluation();
}
@JsonIgnore
public abstract AlarmConditionType getType();

5
common/data/src/main/java/org/thingsboard/server/common/data/alarm/rule/condition/expression/AlarmConditionExpression.java

@ -32,4 +32,9 @@ public interface AlarmConditionExpression {
@JsonIgnore
AlarmConditionExpressionType getType();
@JsonIgnore
default boolean requiresScheduledReevaluation() {
return false;
}
}

19
common/data/src/main/java/org/thingsboard/server/common/data/alarm/rule/condition/expression/AlarmConditionFilter.java

@ -17,8 +17,11 @@ package org.thingsboard.server.common.data.alarm.rule.condition.expression;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import org.thingsboard.server.common.data.alarm.rule.condition.expression.predicate.ComplexFilterPredicate;
import org.thingsboard.server.common.data.alarm.rule.condition.expression.predicate.FilterPredicateType;
import org.thingsboard.server.common.data.alarm.rule.condition.expression.predicate.KeyFilterPredicate;
import org.thingsboard.server.common.data.query.EntityKeyValueType;
@ -34,7 +37,21 @@ public class AlarmConditionFilter implements Serializable {
private EntityKeyValueType valueType;
private ComplexOperation operation;
@Valid
@NotNull
@NotEmpty
private List<KeyFilterPredicate> predicates;
public boolean hasPredicate(FilterPredicateType type) {
return containsPredicate(predicates, type);
}
private boolean containsPredicate(List<KeyFilterPredicate> predicates, FilterPredicateType type) {
return predicates.stream().anyMatch(predicate -> {
if (predicate instanceof ComplexFilterPredicate complexPredicate) {
return containsPredicate(complexPredicate.getPredicates(), type);
} else {
return predicate.getType() == type;
}
});
}
}

6
common/data/src/main/java/org/thingsboard/server/common/data/alarm/rule/condition/expression/SimpleAlarmConditionExpression.java

@ -20,6 +20,7 @@ import jakarta.validation.constraints.NotEmpty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.thingsboard.server.common.data.alarm.rule.condition.expression.predicate.FilterPredicateType;
import java.util.List;
@ -38,4 +39,9 @@ public class SimpleAlarmConditionExpression implements AlarmConditionExpression
return AlarmConditionExpressionType.SIMPLE;
}
@Override
public boolean requiresScheduledReevaluation() {
return filters.stream().anyMatch(filter -> filter.hasPredicate(FilterPredicateType.NO_DATA));
}
}

1
common/data/src/main/java/org/thingsboard/server/common/data/alarm/rule/condition/expression/predicate/FilterPredicateType.java

@ -19,5 +19,6 @@ public enum FilterPredicateType {
STRING,
NUMERIC,
BOOLEAN,
NO_DATA,
COMPLEX
}

4
common/data/src/main/java/org/thingsboard/server/common/data/alarm/rule/condition/expression/predicate/KeyFilterPredicate.java

@ -27,7 +27,9 @@ import java.io.Serializable;
@Type(value = StringFilterPredicate.class, name = "STRING"),
@Type(value = NumericFilterPredicate.class, name = "NUMERIC"),
@Type(value = BooleanFilterPredicate.class, name = "BOOLEAN"),
@Type(value = ComplexFilterPredicate.class, name = "COMPLEX")})
@Type(value = NoDataFilterPredicate.class, name = "NO_DATA"),
@Type(value = ComplexFilterPredicate.class, name = "COMPLEX")
})
public interface KeyFilterPredicate extends Serializable {
@JsonIgnore

39
common/data/src/main/java/org/thingsboard/server/common/data/alarm/rule/condition/expression/predicate/NoDataFilterPredicate.java

@ -0,0 +1,39 @@
/**
* Copyright © 2016-2025 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.common.data.alarm.rule.condition.expression.predicate;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import org.thingsboard.server.common.data.alarm.rule.condition.AlarmConditionValue;
import java.util.concurrent.TimeUnit;
@Data
public class NoDataFilterPredicate implements KeyFilterPredicate {
@NotNull
private TimeUnit unit;
@Valid
@NotNull
private AlarmConditionValue<Long> duration;
@Override
public FilterPredicateType getType() {
return FilterPredicateType.NO_DATA;
}
}
Loading…
Cancel
Save