Browse Source

Merge pull request #14794 from thingsboard/cfs/handling-tenant-profile-update

Handling update of minAllowedScheduledUpdateIntervalInSecForCF and duplicationIntervalInSecForCF in running CFs + updated default values in profile configuration
pull/14815/head
Viacheslav Klimov 5 months ago
committed by GitHub
parent
commit
037d9d3500
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 4
      application/src/main/data/upgrade/basic/schema_update.sql
  2. 4
      application/src/main/java/org/thingsboard/server/controller/TenantProfileController.java
  3. 10
      application/src/main/java/org/thingsboard/server/service/cf/ctx/state/CalculatedFieldCtx.java
  4. 29
      application/src/main/java/org/thingsboard/server/service/cf/ctx/state/HasEntityLimit.java
  5. 8
      application/src/main/java/org/thingsboard/server/service/cf/ctx/state/aggregation/RelatedEntitiesAggregationCalculatedFieldState.java
  6. 18
      application/src/main/java/org/thingsboard/server/service/cf/ctx/state/aggregation/RelatedEntitiesArgumentEntry.java
  7. 10
      application/src/main/java/org/thingsboard/server/service/cf/ctx/state/propagation/PropagationArgumentEntry.java
  8. 8
      common/data/src/main/java/org/thingsboard/server/common/data/tenant/profile/DefaultTenantProfileConfiguration.java
  9. 4
      ui-ngx/src/app/shared/models/tenant.model.ts

4
application/src/main/data/upgrade/basic/schema_update.sql

@ -21,8 +21,8 @@ SET profile_data = jsonb_set(
profile_data, profile_data,
'{configuration}', '{configuration}',
jsonb_build_object( jsonb_build_object(
'minAllowedScheduledUpdateIntervalInSecForCF', 60, 'minAllowedScheduledUpdateIntervalInSecForCF', 10,
'maxRelationLevelPerCfArgument', 10, 'maxRelationLevelPerCfArgument', 2,
'maxRelatedEntitiesToReturnPerCfArgument', 100, 'maxRelatedEntitiesToReturnPerCfArgument', 100,
'minAllowedDeduplicationIntervalInSecForCF', 10, 'minAllowedDeduplicationIntervalInSecForCF', 10,
'minAllowedAggregationIntervalInSecForCF', 60, 'minAllowedAggregationIntervalInSecForCF', 60,

4
application/src/main/java/org/thingsboard/server/controller/TenantProfileController.java

@ -161,8 +161,8 @@ public class TenantProfileController extends BaseController {
" \"warnThreshold\": 0,\n" + " \"warnThreshold\": 0,\n" +
" \"maxCalculatedFieldsPerEntity\": 5,\n" + " \"maxCalculatedFieldsPerEntity\": 5,\n" +
" \"maxArgumentsPerCF\": 10,\n" + " \"maxArgumentsPerCF\": 10,\n" +
" \"minAllowedScheduledUpdateIntervalInSecForCF\": 60,\n" + " \"minAllowedScheduledUpdateIntervalInSecForCF\": 10,\n" +
" \"maxRelationLevelPerCfArgument\": 10,\n" + " \"maxRelationLevelPerCfArgument\": 2,\n" +
" \"maxRelatedEntitiesToReturnPerCfArgument\": 100,\n" + " \"maxRelatedEntitiesToReturnPerCfArgument\": 100,\n" +
" \"maxDataPointsPerRollingArg\": 1000,\n" + " \"maxDataPointsPerRollingArg\": 1000,\n" +
" \"maxStateSizeInKBytes\": 32,\n" + " \"maxStateSizeInKBytes\": 32,\n" +

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

@ -129,6 +129,8 @@ public class CalculatedFieldCtx implements Closeable {
private long cfCheckReevaluationIntervalMillis; private long cfCheckReevaluationIntervalMillis;
private long alarmReevaluationIntervalMillis; private long alarmReevaluationIntervalMillis;
private long maxRelatedEntitiesPerCfArgument; private long maxRelatedEntitiesPerCfArgument;
private long minScheduledUpdateIntervalMillis;
private long minDeduplicationIntervalMillis;
private Argument propagationArgument; private Argument propagationArgument;
private boolean applyExpressionForResolvedArguments; private boolean applyExpressionForResolvedArguments;
@ -312,6 +314,8 @@ public class CalculatedFieldCtx implements Closeable {
this.cfCheckReevaluationIntervalMillis = TimeUnit.SECONDS.toMillis(config.getCfReevaluationCheckInterval()); this.cfCheckReevaluationIntervalMillis = TimeUnit.SECONDS.toMillis(config.getCfReevaluationCheckInterval());
this.alarmReevaluationIntervalMillis = TimeUnit.SECONDS.toMillis(config.getAlarmsReevaluationInterval()); this.alarmReevaluationIntervalMillis = TimeUnit.SECONDS.toMillis(config.getAlarmsReevaluationInterval());
this.maxRelatedEntitiesPerCfArgument = config.getMaxRelatedEntitiesToReturnPerCfArgument(); this.maxRelatedEntitiesPerCfArgument = config.getMaxRelatedEntitiesToReturnPerCfArgument();
this.minScheduledUpdateIntervalMillis = TimeUnit.SECONDS.toMillis(config.getMinAllowedScheduledUpdateIntervalInSecForCF());
this.minDeduplicationIntervalMillis = TimeUnit.SECONDS.toMillis(config.getMinAllowedDeduplicationIntervalInSecForCF());
}); });
} }
@ -763,9 +767,7 @@ public class CalculatedFieldCtx implements Closeable {
} }
public boolean hasRelatedEntities() { public boolean hasRelatedEntities() {
return CalculatedFieldType.GEOFENCING == cfType return cfHasRelationPathQuerySource;
|| CalculatedFieldType.PROPAGATION == cfType
|| CalculatedFieldType.RELATED_ENTITIES_AGGREGATION == cfType;
} }
public boolean shouldFetchRelatedEntities(CalculatedFieldState state) { public boolean shouldFetchRelatedEntities(CalculatedFieldState state) {
@ -781,7 +783,7 @@ public class CalculatedFieldCtx implements Closeable {
if (scheduledRefreshSupported.getLastScheduledRefreshTs() == DEFAULT_LAST_UPDATE_TS) { if (scheduledRefreshSupported.getLastScheduledRefreshTs() == DEFAULT_LAST_UPDATE_TS) {
return true; return true;
} }
return scheduledRefreshSupported.getLastScheduledRefreshTs() < System.currentTimeMillis() - scheduledUpdateIntervalMillis; return scheduledRefreshSupported.getLastScheduledRefreshTs() < System.currentTimeMillis() - Math.max(scheduledUpdateIntervalMillis, minScheduledUpdateIntervalMillis);
} }
@Override @Override

29
application/src/main/java/org/thingsboard/server/service/cf/ctx/state/HasEntityLimit.java

@ -0,0 +1,29 @@
/**
* Copyright © 2016-2026 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.service.cf.ctx.state;
public interface HasEntityLimit {
default void checkEntityLimit(int currentEntitiesCount, CalculatedFieldCtx ctx) {
if (currentEntitiesCount >= ctx.getMaxRelatedEntitiesPerCfArgument()) {
throw new IllegalArgumentException(
"Exceeded the maximum allowed related entities per argument '"
+ ctx.getMaxRelatedEntitiesPerCfArgument() + "'. Increase the limit in the tenant profile configuration."
);
}
}
}

8
application/src/main/java/org/thingsboard/server/service/cf/ctx/state/aggregation/RelatedEntitiesAggregationCalculatedFieldState.java

@ -183,7 +183,7 @@ public class RelatedEntitiesAggregationCalculatedFieldState extends BaseCalculat
} }
public void scheduleReevaluation() { public void scheduleReevaluation() {
ScheduledFuture<?> future = ctx.scheduleReevaluation(deduplicationIntervalMs, actorCtx); ScheduledFuture<?> future = ctx.scheduleReevaluation(getEnforcedDeduplicationIntervalMillis(), actorCtx);
if (future != null) { if (future != null) {
reevaluationFuture = future; reevaluationFuture = future;
} }
@ -209,11 +209,15 @@ public class RelatedEntitiesAggregationCalculatedFieldState extends BaseCalculat
} }
private boolean shouldRecalculate() { private boolean shouldRecalculate() {
boolean intervalPassed = lastMetricsEvalTs <= System.currentTimeMillis() - deduplicationIntervalMs; boolean intervalPassed = lastMetricsEvalTs <= System.currentTimeMillis() - getEnforcedDeduplicationIntervalMillis();
boolean argsUpdatedDuringInterval = lastArgsRefreshTs > lastMetricsEvalTs; boolean argsUpdatedDuringInterval = lastArgsRefreshTs > lastMetricsEvalTs;
return intervalPassed && argsUpdatedDuringInterval; return intervalPassed && argsUpdatedDuringInterval;
} }
private long getEnforcedDeduplicationIntervalMillis() {
return Math.max(deduplicationIntervalMs, ctx.getMinDeduplicationIntervalMillis());
}
private Map<EntityId, Map<String, ArgumentEntry>> prepareInputs() { private Map<EntityId, Map<String, ArgumentEntry>> prepareInputs() {
Map<EntityId, Map<String, ArgumentEntry>> inputs = new HashMap<>(); Map<EntityId, Map<String, ArgumentEntry>> inputs = new HashMap<>();
for (Map.Entry<String, ArgumentEntry> argEntry : arguments.entrySet()) { for (Map.Entry<String, ArgumentEntry> argEntry : arguments.entrySet()) {

18
application/src/main/java/org/thingsboard/server/service/cf/ctx/state/aggregation/RelatedEntitiesArgumentEntry.java

@ -24,6 +24,7 @@ import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.service.cf.ctx.state.ArgumentEntry; import org.thingsboard.server.service.cf.ctx.state.ArgumentEntry;
import org.thingsboard.server.service.cf.ctx.state.ArgumentEntryType; import org.thingsboard.server.service.cf.ctx.state.ArgumentEntryType;
import org.thingsboard.server.service.cf.ctx.state.CalculatedFieldCtx; import org.thingsboard.server.service.cf.ctx.state.CalculatedFieldCtx;
import org.thingsboard.server.service.cf.ctx.state.HasEntityLimit;
import org.thingsboard.server.service.cf.ctx.state.HasLatestTs; import org.thingsboard.server.service.cf.ctx.state.HasLatestTs;
import org.thingsboard.server.service.cf.ctx.state.SingleValueArgumentEntry; import org.thingsboard.server.service.cf.ctx.state.SingleValueArgumentEntry;
@ -34,7 +35,7 @@ import static org.thingsboard.server.service.cf.ctx.state.BaseCalculatedFieldSta
@Data @Data
@AllArgsConstructor @AllArgsConstructor
public class RelatedEntitiesArgumentEntry implements ArgumentEntry, HasLatestTs { public class RelatedEntitiesArgumentEntry implements ArgumentEntry, HasLatestTs, HasEntityLimit {
private final Map<EntityId, ArgumentEntry> entityInputs; private final Map<EntityId, ArgumentEntry> entityInputs;
@ -66,18 +67,18 @@ public class RelatedEntitiesArgumentEntry implements ArgumentEntry, HasLatestTs
@Override @Override
public boolean updateEntry(ArgumentEntry entry, CalculatedFieldCtx ctx) { public boolean updateEntry(ArgumentEntry entry, CalculatedFieldCtx ctx) {
if (entry instanceof RelatedEntitiesArgumentEntry relatedEntitiesArgumentEntry) { if (entry instanceof RelatedEntitiesArgumentEntry relatedEntitiesArgumentEntry) {
checkRelatedEntitiesNumber(ctx); checkEntityLimit(entityInputs.size(), ctx);
entityInputs.putAll(relatedEntitiesArgumentEntry.entityInputs); entityInputs.putAll(relatedEntitiesArgumentEntry.entityInputs);
} else if (entry instanceof SingleValueArgumentEntry singleValueArgumentEntry) { } else if (entry instanceof SingleValueArgumentEntry singleValueArgumentEntry) {
if (entry.isForceResetPrevious()) { if (entry.isForceResetPrevious()) {
checkRelatedEntitiesNumber(ctx); checkEntityLimit(entityInputs.size(), ctx);
entityInputs.put(singleValueArgumentEntry.getEntityId(), singleValueArgumentEntry); entityInputs.put(singleValueArgumentEntry.getEntityId(), singleValueArgumentEntry);
} else { } else {
ArgumentEntry argumentEntry = entityInputs.get(singleValueArgumentEntry.getEntityId()); ArgumentEntry argumentEntry = entityInputs.get(singleValueArgumentEntry.getEntityId());
if (argumentEntry != null) { if (argumentEntry != null) {
argumentEntry.updateEntry(singleValueArgumentEntry, ctx); argumentEntry.updateEntry(singleValueArgumentEntry, ctx);
} else { } else {
checkRelatedEntitiesNumber(ctx); checkEntityLimit(entityInputs.size(), ctx);
entityInputs.put(singleValueArgumentEntry.getEntityId(), singleValueArgumentEntry); entityInputs.put(singleValueArgumentEntry.getEntityId(), singleValueArgumentEntry);
} }
} }
@ -87,15 +88,6 @@ public class RelatedEntitiesArgumentEntry implements ArgumentEntry, HasLatestTs
return true; return true;
} }
private void checkRelatedEntitiesNumber(CalculatedFieldCtx ctx) {
if (entityInputs.size() >= ctx.getMaxRelatedEntitiesPerCfArgument()) {
throw new IllegalArgumentException(
"Exceeded the maximum allowed related entities per argument '"
+ ctx.getMaxRelatedEntitiesPerCfArgument() + "'. Increase the limit in the tenant profile configuration."
);
}
}
@Override @Override
public boolean isEmpty() { public boolean isEmpty() {
return entityInputs.isEmpty(); return entityInputs.isEmpty();

10
application/src/main/java/org/thingsboard/server/service/cf/ctx/state/propagation/PropagationArgumentEntry.java

@ -22,6 +22,7 @@ import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.service.cf.ctx.state.ArgumentEntry; import org.thingsboard.server.service.cf.ctx.state.ArgumentEntry;
import org.thingsboard.server.service.cf.ctx.state.ArgumentEntryType; import org.thingsboard.server.service.cf.ctx.state.ArgumentEntryType;
import org.thingsboard.server.service.cf.ctx.state.CalculatedFieldCtx; import org.thingsboard.server.service.cf.ctx.state.CalculatedFieldCtx;
import org.thingsboard.server.service.cf.ctx.state.HasEntityLimit;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
@ -30,7 +31,7 @@ import java.util.List;
import java.util.Set; import java.util.Set;
@Data @Data
public class PropagationArgumentEntry implements ArgumentEntry { public class PropagationArgumentEntry implements ArgumentEntry, HasEntityLimit {
private Set<EntityId> entityIds; private Set<EntityId> entityIds;
private transient List<EntityId> added; private transient List<EntityId> added;
@ -93,12 +94,7 @@ public class PropagationArgumentEntry implements ArgumentEntry {
private boolean checkAdded(Collection<EntityId> updatedIds, CalculatedFieldCtx ctx) { private boolean checkAdded(Collection<EntityId> updatedIds, CalculatedFieldCtx ctx) {
for (EntityId id : updatedIds) { for (EntityId id : updatedIds) {
if (entityIds.size() >= ctx.getMaxRelatedEntitiesPerCfArgument()) { checkEntityLimit(entityIds.size(), ctx);
throw new IllegalArgumentException(
"Exceeded the maximum allowed related entities per argument '"
+ ctx.getMaxRelatedEntitiesPerCfArgument() + "'. Increase the limit in the tenant profile configuration."
);
}
if (entityIds.add(id)) { if (entityIds.add(id)) {
if (added == null) { if (added == null) {
added = new ArrayList<>(); added = new ArrayList<>();

8
common/data/src/main/java/org/thingsboard/server/common/data/tenant/profile/DefaultTenantProfileConfiguration.java

@ -172,12 +172,12 @@ public class DefaultTenantProfileConfiguration implements TenantProfileConfigura
private long maxCalculatedFieldsPerEntity = 5; private long maxCalculatedFieldsPerEntity = 5;
@Schema(example = "10") @Schema(example = "10")
private long maxArgumentsPerCF = 10; private long maxArgumentsPerCF = 10;
@Schema(example = "60")
private int minAllowedScheduledUpdateIntervalInSecForCF = 60;
@Builder.Default
@Schema(example = "10") @Schema(example = "10")
private int minAllowedScheduledUpdateIntervalInSecForCF = 10;
@Builder.Default
@Schema(example = "2")
@Positive @Positive
private int maxRelationLevelPerCfArgument = 10; private int maxRelationLevelPerCfArgument = 2;
@Builder.Default @Builder.Default
@Schema(example = "100") @Schema(example = "100")
@Positive @Positive

4
ui-ngx/src/app/shared/models/tenant.model.ts

@ -179,11 +179,11 @@ export function createTenantProfileConfiguration(type: TenantProfileType): Tenan
maxCalculatedFieldsPerEntity: 5, maxCalculatedFieldsPerEntity: 5,
maxArgumentsPerCF: 10, maxArgumentsPerCF: 10,
maxDataPointsPerRollingArg: 1000, maxDataPointsPerRollingArg: 1000,
maxRelationLevelPerCfArgument: 10, maxRelationLevelPerCfArgument: 2,
minAllowedDeduplicationIntervalInSecForCF: 10, minAllowedDeduplicationIntervalInSecForCF: 10,
minAllowedAggregationIntervalInSecForCF: 60, minAllowedAggregationIntervalInSecForCF: 60,
maxRelatedEntitiesToReturnPerCfArgument: 100, maxRelatedEntitiesToReturnPerCfArgument: 100,
minAllowedScheduledUpdateIntervalInSecForCF: 0, minAllowedScheduledUpdateIntervalInSecForCF: 10,
intermediateAggregationIntervalInSecForCF: 300, intermediateAggregationIntervalInSecForCF: 300,
cfReevaluationCheckInterval: 60, cfReevaluationCheckInterval: 60,
alarmsReevaluationInterval: 60, alarmsReevaluationInterval: 60,

Loading…
Cancel
Save