From 48a64e3b10850eaa7f37d4d559db25d0ec96edaf Mon Sep 17 00:00:00 2001 From: dshvaika Date: Thu, 4 Dec 2025 17:22:16 +0200 Subject: [PATCH 1/8] Added support of relations lifecycle updates for propagation CF --- ...CalculatedFieldEntityMessageProcessor.java | 34 ++++++++++++++----- ...alculatedFieldManagerMessageProcessor.java | 3 +- .../propagation/PropagationArgumentEntry.java | 11 ++++++ .../PropagationCalculatedFieldState.java | 20 ++++++++--- .../cf/CalculatedFieldIntegrationTest.java | 16 +++++++++ .../state/PropagationArgumentEntryTest.java | 28 +++++++++++++++ .../PropagationCalculatedFieldStateTest.java | 28 ++++++++++++++- .../configuration/HasRelationPathLevel.java | 24 +++++++++++++ ...opagationCalculatedFieldConfiguration.java | 2 +- ...onPathQueryDynamicSourceConfiguration.java | 2 -- ...gregationCalculatedFieldConfiguration.java | 3 +- .../common/data/util/CollectionsUtil.java | 8 +++++ 12 files changed, 161 insertions(+), 18 deletions(-) create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/HasRelationPathLevel.java diff --git a/application/src/main/java/org/thingsboard/server/actors/calculatedField/CalculatedFieldEntityMessageProcessor.java b/application/src/main/java/org/thingsboard/server/actors/calculatedField/CalculatedFieldEntityMessageProcessor.java index 2685e7f434..d3fcb8e2d8 100644 --- a/application/src/main/java/org/thingsboard/server/actors/calculatedField/CalculatedFieldEntityMessageProcessor.java +++ b/application/src/main/java/org/thingsboard/server/actors/calculatedField/CalculatedFieldEntityMessageProcessor.java @@ -36,6 +36,7 @@ import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.kv.StringDataEntry; import org.thingsboard.server.common.data.msg.TbMsgType; +import org.thingsboard.server.common.data.util.CollectionsUtil; import org.thingsboard.server.common.msg.CalculatedFieldStatePartitionRestoreMsg; import org.thingsboard.server.common.msg.cf.CalculatedFieldPartitionChangeMsg; import org.thingsboard.server.common.msg.queue.ServiceType; @@ -56,6 +57,8 @@ import org.thingsboard.server.service.cf.ctx.state.aggregation.RelatedEntitiesAg import org.thingsboard.server.service.cf.ctx.state.alarm.AlarmCalculatedFieldState; import org.thingsboard.server.service.cf.ctx.state.geofencing.GeofencingArgumentEntry; import org.thingsboard.server.service.cf.ctx.state.geofencing.GeofencingCalculatedFieldState; +import org.thingsboard.server.service.cf.ctx.state.propagation.PropagationArgumentEntry; +import org.thingsboard.server.service.cf.ctx.state.propagation.PropagationCalculatedFieldState; import java.util.ArrayList; import java.util.Collection; @@ -71,6 +74,7 @@ import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; import static org.thingsboard.server.common.data.DataConstants.REEVALUATION_MSG; +import static org.thingsboard.server.common.data.cf.configuration.PropagationCalculatedFieldConfiguration.PROPAGATION_CONFIG_ARGUMENT; import static org.thingsboard.server.utils.CalculatedFieldArgumentUtils.createStateByType; /** @@ -225,17 +229,27 @@ public class CalculatedFieldEntityMessageProcessor extends AbstractContextAwareM var callback = new MultipleTbCallback(CALLBACKS_PER_CF, msg.getCallback()); var state = states.get(ctx.getCfId()); try { - Map updatedArgs = new HashMap<>(); if (state == null) { state = createState(ctx); - } else { - if (state instanceof RelatedEntitiesAggregationCalculatedFieldState relatedEntitiesAggState) { - Map fetchedArgs = cfService.fetchArgsFromDb(tenantId, msg.getRelatedEntityId(), ctx.getArguments()); - updatedArgs = relatedEntitiesAggState.updateEntityData(setEntityIdToSingleEntityArguments(msg.getRelatedEntityId(), fetchedArgs)); + } + Map updatedArgs = null; + if (state instanceof RelatedEntitiesAggregationCalculatedFieldState relatedEntitiesAggState) { + Map fetchedArgs = cfService.fetchArgsFromDb(tenantId, msg.getRelatedEntityId(), ctx.getArguments()); + updatedArgs = relatedEntitiesAggState.updateEntityData(setEntityIdToSingleEntityArguments(msg.getRelatedEntityId(), fetchedArgs)); + } + if (state instanceof PropagationCalculatedFieldState propagationState) { + PropagationArgumentEntry propagationArgument = propagationState.getPropagationArgument(); + boolean added = propagationArgument.addPropagationEntityId(msg.getRelatedEntityId()); + if (added) { + updatedArgs = Map.of(PROPAGATION_CONFIG_ARGUMENT, new PropagationArgumentEntry(List.of(msg.getRelatedEntityId()))); } + } - state.checkStateSize(new CalculatedFieldEntityCtxId(tenantId, ctx.getCfId(), entityId), ctx.getMaxStateSize()); + if (CollectionsUtil.isEmpty(updatedArgs)) { + msg.getCallback().onSuccess(); + return; } + state.checkStateSize(new CalculatedFieldEntityCtxId(tenantId, ctx.getCfId(), entityId), ctx.getMaxStateSize()); if (state.isSizeOk()) { processStateIfReady(state, updatedArgs, ctx, Collections.singletonList(ctx.getCfId()), null, null, callback); } else { @@ -268,9 +282,13 @@ public class CalculatedFieldEntityMessageProcessor extends AbstractContextAwareM } else { throw new RuntimeException(ctx.getSizeExceedsLimitMessage()); } - } else { - msg.getCallback().onSuccess(); + return; } + if (state instanceof PropagationCalculatedFieldState propagationState) { + PropagationArgumentEntry propagationArgument = propagationState.getPropagationArgument(); + propagationArgument.removePropagationEntityId(msg.getRelatedEntityId()); + } + msg.getCallback().onSuccess(); } public void process(EntityCalculatedFieldTelemetryMsg msg) throws CalculatedFieldException { diff --git a/application/src/main/java/org/thingsboard/server/actors/calculatedField/CalculatedFieldManagerMessageProcessor.java b/application/src/main/java/org/thingsboard/server/actors/calculatedField/CalculatedFieldManagerMessageProcessor.java index b19ad1a8b4..838b25fca0 100644 --- a/application/src/main/java/org/thingsboard/server/actors/calculatedField/CalculatedFieldManagerMessageProcessor.java +++ b/application/src/main/java/org/thingsboard/server/actors/calculatedField/CalculatedFieldManagerMessageProcessor.java @@ -36,6 +36,7 @@ import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.cf.CalculatedField; import org.thingsboard.server.common.data.cf.CalculatedFieldLink; import org.thingsboard.server.common.data.cf.CalculatedFieldType; +import org.thingsboard.server.common.data.cf.configuration.HasRelationPathLevel; import org.thingsboard.server.common.data.cf.configuration.aggregation.RelatedEntitiesAggregationCalculatedFieldConfiguration; import org.thingsboard.server.common.data.id.AssetId; import org.thingsboard.server.common.data.id.CalculatedFieldId; @@ -363,7 +364,7 @@ public class CalculatedFieldManagerMessageProcessor extends AbstractContextAware List matchingCfs = cfsByEntityIdAndProfile.stream() .filter(cf -> { - if (cf.getCalculatedField().getConfiguration() instanceof RelatedEntitiesAggregationCalculatedFieldConfiguration config) { + if (cf.getCalculatedField().getConfiguration() instanceof HasRelationPathLevel config) { RelationPathLevel relation = config.getRelation(); return direction.equals(relation.direction()) && relationType.equals(relation.relationType()); } diff --git a/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/propagation/PropagationArgumentEntry.java b/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/propagation/PropagationArgumentEntry.java index 81009da5e5..ebb23a0794 100644 --- a/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/propagation/PropagationArgumentEntry.java +++ b/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/propagation/PropagationArgumentEntry.java @@ -70,4 +70,15 @@ public class PropagationArgumentEntry implements ArgumentEntry { return new TbelCfPropagationArg(propagationEntityIds); } + public boolean addPropagationEntityId(EntityId propagationEntityId) { + if (propagationEntityIds.contains(propagationEntityId)) { + return false; + } + return propagationEntityIds.add(propagationEntityId); + } + + public void removePropagationEntityId(EntityId relatedEntityId) { + propagationEntityIds.remove(relatedEntityId); + } + } diff --git a/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/propagation/PropagationCalculatedFieldState.java b/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/propagation/PropagationCalculatedFieldState.java index 32714b9b65..991d3e66dd 100644 --- a/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/propagation/PropagationCalculatedFieldState.java +++ b/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/propagation/PropagationCalculatedFieldState.java @@ -25,6 +25,7 @@ import org.thingsboard.server.common.data.cf.CalculatedFieldType; import org.thingsboard.server.common.data.cf.configuration.Output; import org.thingsboard.server.common.data.cf.configuration.OutputType; import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.util.CollectionsUtil; import org.thingsboard.server.service.cf.CalculatedFieldResult; import org.thingsboard.server.service.cf.PropagationCalculatedFieldResult; import org.thingsboard.server.service.cf.TelemetryCalculatedFieldResult; @@ -34,6 +35,7 @@ import org.thingsboard.server.service.cf.ctx.state.ScriptCalculatedFieldState; import org.thingsboard.server.service.cf.ctx.state.SingleValueArgumentEntry; import java.util.ArrayList; +import java.util.List; import java.util.Map; import static org.thingsboard.server.common.data.cf.configuration.PropagationCalculatedFieldConfiguration.PROPAGATION_CONFIG_ARGUMENT; @@ -63,20 +65,26 @@ public class PropagationCalculatedFieldState extends ScriptCalculatedFieldState @Override public ListenableFuture performCalculation(Map updatedArgs, CalculatedFieldCtx ctx) { - ArgumentEntry argumentEntry = arguments.get(PROPAGATION_CONFIG_ARGUMENT); - if (!(argumentEntry instanceof PropagationArgumentEntry propagationArgumentEntry) || propagationArgumentEntry.isEmpty()) { + List propagationEntityIds; + if (CollectionsUtil.isNotEmpty(updatedArgs) && updatedArgs.size() == 1 && updatedArgs.containsKey(PROPAGATION_CONFIG_ARGUMENT)) { + propagationEntityIds = ((PropagationArgumentEntry) updatedArgs.get(PROPAGATION_CONFIG_ARGUMENT)).getPropagationEntityIds(); + } else { + PropagationArgumentEntry propagationArgumentEntry = (PropagationArgumentEntry) arguments.get(PROPAGATION_CONFIG_ARGUMENT); + propagationEntityIds = propagationArgumentEntry.getPropagationEntityIds(); + } + if (propagationEntityIds.isEmpty()) { return Futures.immediateFuture(PropagationCalculatedFieldResult.builder().build()); } if (ctx.isApplyExpressionForResolvedArguments()) { return Futures.transform(super.performCalculation(updatedArgs, ctx), telemetryCfResult -> PropagationCalculatedFieldResult.builder() - .propagationEntityIds(propagationArgumentEntry.getPropagationEntityIds()) + .propagationEntityIds(propagationEntityIds) .result((TelemetryCalculatedFieldResult) telemetryCfResult) .build(), MoreExecutors.directExecutor()); } return Futures.immediateFuture(PropagationCalculatedFieldResult.builder() - .propagationEntityIds(propagationArgumentEntry.getPropagationEntityIds()) + .propagationEntityIds(propagationEntityIds) .result(toTelemetryResult(ctx)) .build()); } @@ -105,4 +113,8 @@ public class PropagationCalculatedFieldState extends ScriptCalculatedFieldState return telemetryCfBuilder.build(); } + public PropagationArgumentEntry getPropagationArgument() { + return (PropagationArgumentEntry) arguments.get(PROPAGATION_CONFIG_ARGUMENT); + } + } diff --git a/application/src/test/java/org/thingsboard/server/cf/CalculatedFieldIntegrationTest.java b/application/src/test/java/org/thingsboard/server/cf/CalculatedFieldIntegrationTest.java index af0c1b9909..cdb65425dc 100644 --- a/application/src/test/java/org/thingsboard/server/cf/CalculatedFieldIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/cf/CalculatedFieldIntegrationTest.java @@ -1146,6 +1146,22 @@ public class CalculatedFieldIntegrationTest extends CalculatedFieldControllerTes assertThat(telemetry2.get("temperatureComputed").get(0).get("ts").asText()).isEqualTo(Long.toString(newTs)); assertThat(telemetry2.get("temperatureComputed").get(0).get("value").asDouble()).isEqualTo(25); }); + + Asset asset3 = createAsset("Propagated Asset 3", null); + EntityRelation rel3 = new EntityRelation(asset3.getId(), device.getId(), EntityRelation.CONTAINS_TYPE); + doPost("/api/relation", rel3).andExpect(status().isOk()); + + // --- Assert propagated calculation (arguments-only mode after update) --- + await().alias("propagation args-only to new entity after relation creation") + .atMost(TIMEOUT, TimeUnit.SECONDS) + .pollInterval(POLL_INTERVAL, TimeUnit.SECONDS) + .untilAsserted(() -> { + ObjectNode telemetry = getLatestTelemetry(asset3.getId(), "temperatureComputed"); + assertThat(telemetry).isNotNull(); + assertThat(telemetry.get("temperatureComputed").get(0).get("ts").asText()).isEqualTo(Long.toString(newTs)); + assertThat(telemetry.get("temperatureComputed").get(0).get("value").asDouble()).isEqualTo(25); + }); + } @Test diff --git a/application/src/test/java/org/thingsboard/server/service/cf/ctx/state/PropagationArgumentEntryTest.java b/application/src/test/java/org/thingsboard/server/service/cf/ctx/state/PropagationArgumentEntryTest.java index 14a1b629c1..32e31e7a9e 100644 --- a/application/src/test/java/org/thingsboard/server/service/cf/ctx/state/PropagationArgumentEntryTest.java +++ b/application/src/test/java/org/thingsboard/server/service/cf/ctx/state/PropagationArgumentEntryTest.java @@ -124,4 +124,32 @@ public class PropagationArgumentEntryTest { assertThat((List) tbelCfPropagationArg.getValue()).isEmpty(); } + @Test + void testAddNewPropagationEntityIdToEmptyArgument() { + PropagationArgumentEntry empty = new PropagationArgumentEntry(List.of()); + assertThat(empty.addPropagationEntityId(ENTITY_1_ID)).isTrue(); + assertThat(empty.getPropagationEntityIds()).containsExactly(ENTITY_1_ID); + } + + @Test + void testAddNewPropagationEntityIdThatAlreadyExists() { + PropagationArgumentEntry hasEntity = new PropagationArgumentEntry(List.of(ENTITY_1_ID)); + assertThat(hasEntity.addPropagationEntityId(ENTITY_1_ID)).isFalse(); + assertThat(hasEntity.getPropagationEntityIds()).containsExactly(ENTITY_1_ID); + } + + @Test + void testAddNewPropagationEntityId() { + PropagationArgumentEntry hasEntity = new PropagationArgumentEntry(List.of(ENTITY_1_ID, ENTITY_2_ID)); + assertThat(hasEntity.addPropagationEntityId(ENTITY_3_ID)).isTrue(); + assertThat(hasEntity.getPropagationEntityIds()).contains(ENTITY_1_ID, ENTITY_2_ID, ENTITY_3_ID); + } + + @Test + void testRemovePropagationEntityId() { + PropagationArgumentEntry hasEntity = new PropagationArgumentEntry(List.of(ENTITY_1_ID)); + hasEntity.removePropagationEntityId(ENTITY_1_ID); + assertThat(hasEntity.isEmpty()).isTrue(); + } + } diff --git a/application/src/test/java/org/thingsboard/server/service/cf/ctx/state/PropagationCalculatedFieldStateTest.java b/application/src/test/java/org/thingsboard/server/service/cf/ctx/state/PropagationCalculatedFieldStateTest.java index 202b88b2eb..99c8f5631b 100644 --- a/application/src/test/java/org/thingsboard/server/service/cf/ctx/state/PropagationCalculatedFieldStateTest.java +++ b/application/src/test/java/org/thingsboard/server/service/cf/ctx/state/PropagationCalculatedFieldStateTest.java @@ -221,6 +221,28 @@ public class PropagationCalculatedFieldStateTest { assertThat(result.getResult()).isEqualTo(expectedNode); } + @Test + void testPropagationWithUpdatedPropagationArgument() throws ExecutionException, InterruptedException { + initCtxAndState(false); + state.getArguments().put(PROPAGATION_CONFIG_ARGUMENT, propagationArgEntry); + state.getArguments().put(TEMPERATURE_ARGUMENT_NAME, singleValueArgEntry); + + PropagationArgumentEntry propagationArgument = state.getPropagationArgument(); + assertThat(propagationArgument).isNotNull().isEqualTo(propagationArgEntry); + + AssetId newEntityId = new AssetId(UUID.fromString("83e2c962-eeae-4708-984e-e6a24760f9c3")); + boolean added = propagationArgument.addPropagationEntityId(newEntityId); + assertThat(added).isTrue(); + + ArgumentEntry argumentEntry = state.getArguments().get(PROPAGATION_CONFIG_ARGUMENT); + assertThat(argumentEntry).isNotNull().isInstanceOf(PropagationArgumentEntry.class); + assertThat(((PropagationArgumentEntry) argumentEntry).getPropagationEntityIds()).containsExactly(ASSET_ID_2, ASSET_ID_1, newEntityId); + + PropagationCalculatedFieldResult propagationCalculatedFieldResult = performCalculation(Map.of(PROPAGATION_CONFIG_ARGUMENT, new PropagationArgumentEntry(List.of(newEntityId)))); + assertThat(propagationCalculatedFieldResult).isNotNull(); + assertThat(propagationCalculatedFieldResult.getPropagationEntityIds()).isNotNull().containsExactly(newEntityId); + } + private CalculatedField getCalculatedField(boolean applyExpressionToResolvedArguments) { CalculatedField calculatedField = new CalculatedField(); calculatedField.setTenantId(TENANT_ID); @@ -254,6 +276,10 @@ public class PropagationCalculatedFieldStateTest { } private PropagationCalculatedFieldResult performCalculation() throws ExecutionException, InterruptedException { - return (PropagationCalculatedFieldResult) state.performCalculation(Collections.emptyMap(), ctx).get(); + return performCalculation(Collections.emptyMap()); + } + + private PropagationCalculatedFieldResult performCalculation(Map updatedArgs) throws ExecutionException, InterruptedException { + return (PropagationCalculatedFieldResult) state.performCalculation(updatedArgs, ctx).get(); } } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/HasRelationPathLevel.java b/common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/HasRelationPathLevel.java new file mode 100644 index 0000000000..40e7441a9b --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/HasRelationPathLevel.java @@ -0,0 +1,24 @@ +/** + * 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.cf.configuration; + +import org.thingsboard.server.common.data.relation.RelationPathLevel; + +public interface HasRelationPathLevel { + + RelationPathLevel getRelation(); + +} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/PropagationCalculatedFieldConfiguration.java b/common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/PropagationCalculatedFieldConfiguration.java index 61d4542eb9..0044822555 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/PropagationCalculatedFieldConfiguration.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/PropagationCalculatedFieldConfiguration.java @@ -27,7 +27,7 @@ import java.util.List; @Data @EqualsAndHashCode(callSuper = true) -public class PropagationCalculatedFieldConfiguration extends BaseCalculatedFieldConfiguration { +public class PropagationCalculatedFieldConfiguration extends BaseCalculatedFieldConfiguration implements HasRelationPathLevel { public static final String PROPAGATION_CONFIG_ARGUMENT = "propagationCtx"; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/RelationPathQueryDynamicSourceConfiguration.java b/common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/RelationPathQueryDynamicSourceConfiguration.java index dc92ff3685..6595e00f1a 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/RelationPathQueryDynamicSourceConfiguration.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/RelationPathQueryDynamicSourceConfiguration.java @@ -15,7 +15,6 @@ */ package org.thingsboard.server.common.data.cf.configuration; -import com.fasterxml.jackson.annotation.JsonIgnore; import lombok.Data; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.relation.EntityRelation; @@ -25,7 +24,6 @@ import org.thingsboard.server.common.data.relation.RelationPathLevel; import org.thingsboard.server.common.data.util.CollectionsUtil; import java.util.List; -import java.util.NoSuchElementException; @Data public class RelationPathQueryDynamicSourceConfiguration implements CfArgumentDynamicSourceConfiguration { diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/aggregation/RelatedEntitiesAggregationCalculatedFieldConfiguration.java b/common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/aggregation/RelatedEntitiesAggregationCalculatedFieldConfiguration.java index 0dee6ee4a4..ecbab0ab94 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/aggregation/RelatedEntitiesAggregationCalculatedFieldConfiguration.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/aggregation/RelatedEntitiesAggregationCalculatedFieldConfiguration.java @@ -22,6 +22,7 @@ import lombok.Data; import org.thingsboard.server.common.data.cf.CalculatedFieldType; import org.thingsboard.server.common.data.cf.configuration.Argument; import org.thingsboard.server.common.data.cf.configuration.ArgumentsBasedCalculatedFieldConfiguration; +import org.thingsboard.server.common.data.cf.configuration.HasRelationPathLevel; import org.thingsboard.server.common.data.cf.configuration.Output; import org.thingsboard.server.common.data.cf.configuration.ScheduledUpdateSupportedCalculatedFieldConfiguration; import org.thingsboard.server.common.data.relation.RelationPathLevel; @@ -29,7 +30,7 @@ import org.thingsboard.server.common.data.relation.RelationPathLevel; import java.util.Map; @Data -public class RelatedEntitiesAggregationCalculatedFieldConfiguration implements ArgumentsBasedCalculatedFieldConfiguration, ScheduledUpdateSupportedCalculatedFieldConfiguration { +public class RelatedEntitiesAggregationCalculatedFieldConfiguration implements ArgumentsBasedCalculatedFieldConfiguration, ScheduledUpdateSupportedCalculatedFieldConfiguration, HasRelationPathLevel { @NotNull private RelationPathLevel relation; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/util/CollectionsUtil.java b/common/data/src/main/java/org/thingsboard/server/common/data/util/CollectionsUtil.java index 0d69db556d..476b63f635 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/util/CollectionsUtil.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/util/CollectionsUtil.java @@ -137,4 +137,12 @@ public class CollectionsUtil { return (Set) Set.of(newSet.toArray()); } + public static boolean isEmpty(Map map) { + return map == null || map.isEmpty(); + } + + public static boolean isNotEmpty(Map map) { + return !isEmpty(map); + } + } From 8bbfcca578d9e695d9907d775ec7152204747470 Mon Sep 17 00:00:00 2001 From: dshvaika Date: Thu, 4 Dec 2025 18:19:26 +0200 Subject: [PATCH 2/8] Added propagation entities to proto state && added reset of readiness status on relation updates --- .../CalculatedFieldEntityMessageProcessor.java | 6 +++++- .../propagation/PropagationArgumentEntry.java | 4 ++-- .../PropagationCalculatedFieldState.java | 4 ++++ .../server/utils/CalculatedFieldUtils.java | 14 ++++++++++++++ .../server/utils/CalculatedFieldUtilsTest.java | 4 ++-- common/proto/src/main/proto/queue.proto | 1 + 6 files changed, 28 insertions(+), 5 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/actors/calculatedField/CalculatedFieldEntityMessageProcessor.java b/application/src/main/java/org/thingsboard/server/actors/calculatedField/CalculatedFieldEntityMessageProcessor.java index d3fcb8e2d8..9d8231956c 100644 --- a/application/src/main/java/org/thingsboard/server/actors/calculatedField/CalculatedFieldEntityMessageProcessor.java +++ b/application/src/main/java/org/thingsboard/server/actors/calculatedField/CalculatedFieldEntityMessageProcessor.java @@ -241,6 +241,7 @@ public class CalculatedFieldEntityMessageProcessor extends AbstractContextAwareM PropagationArgumentEntry propagationArgument = propagationState.getPropagationArgument(); boolean added = propagationArgument.addPropagationEntityId(msg.getRelatedEntityId()); if (added) { + propagationState.resetReadinessStatus(); updatedArgs = Map.of(PROPAGATION_CONFIG_ARGUMENT, new PropagationArgumentEntry(List.of(msg.getRelatedEntityId()))); } } @@ -286,7 +287,10 @@ public class CalculatedFieldEntityMessageProcessor extends AbstractContextAwareM } if (state instanceof PropagationCalculatedFieldState propagationState) { PropagationArgumentEntry propagationArgument = propagationState.getPropagationArgument(); - propagationArgument.removePropagationEntityId(msg.getRelatedEntityId()); + boolean removed = propagationArgument.removePropagationEntityId(msg.getRelatedEntityId()); + if (removed) { + propagationState.resetReadinessStatus(); + } } msg.getCallback().onSuccess(); } diff --git a/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/propagation/PropagationArgumentEntry.java b/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/propagation/PropagationArgumentEntry.java index ebb23a0794..964aa5487e 100644 --- a/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/propagation/PropagationArgumentEntry.java +++ b/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/propagation/PropagationArgumentEntry.java @@ -77,8 +77,8 @@ public class PropagationArgumentEntry implements ArgumentEntry { return propagationEntityIds.add(propagationEntityId); } - public void removePropagationEntityId(EntityId relatedEntityId) { - propagationEntityIds.remove(relatedEntityId); + public boolean removePropagationEntityId(EntityId relatedEntityId) { + return propagationEntityIds.remove(relatedEntityId); } } diff --git a/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/propagation/PropagationCalculatedFieldState.java b/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/propagation/PropagationCalculatedFieldState.java index 991d3e66dd..a6abeb1b32 100644 --- a/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/propagation/PropagationCalculatedFieldState.java +++ b/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/propagation/PropagationCalculatedFieldState.java @@ -117,4 +117,8 @@ public class PropagationCalculatedFieldState extends ScriptCalculatedFieldState return (PropagationArgumentEntry) arguments.get(PROPAGATION_CONFIG_ARGUMENT); } + public void resetReadinessStatus() { + readinessStatus = checkReadiness(requiredArguments, arguments); + } + } diff --git a/application/src/main/java/org/thingsboard/server/utils/CalculatedFieldUtils.java b/application/src/main/java/org/thingsboard/server/utils/CalculatedFieldUtils.java index 09ba7917e9..5fd48398e4 100644 --- a/application/src/main/java/org/thingsboard/server/utils/CalculatedFieldUtils.java +++ b/application/src/main/java/org/thingsboard/server/utils/CalculatedFieldUtils.java @@ -33,6 +33,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.ArgumentIntervalProt import org.thingsboard.server.gen.transport.TransportProtos.CalculatedFieldEntityCtxIdProto; import org.thingsboard.server.gen.transport.TransportProtos.CalculatedFieldIdProto; import org.thingsboard.server.gen.transport.TransportProtos.CalculatedFieldStateProto; +import org.thingsboard.server.gen.transport.TransportProtos.EntityIdProto; import org.thingsboard.server.gen.transport.TransportProtos.GeofencingArgumentProto; import org.thingsboard.server.gen.transport.TransportProtos.GeofencingZoneProto; import org.thingsboard.server.gen.transport.TransportProtos.SingleValueArgumentProto; @@ -57,9 +58,11 @@ import org.thingsboard.server.service.cf.ctx.state.alarm.AlarmRuleState; import org.thingsboard.server.service.cf.ctx.state.geofencing.GeofencingArgumentEntry; import org.thingsboard.server.service.cf.ctx.state.geofencing.GeofencingCalculatedFieldState; import org.thingsboard.server.service.cf.ctx.state.geofencing.GeofencingZoneState; +import org.thingsboard.server.service.cf.ctx.state.propagation.PropagationArgumentEntry; import org.thingsboard.server.service.cf.ctx.state.propagation.PropagationCalculatedFieldState; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Optional; import java.util.TreeMap; @@ -67,6 +70,8 @@ import java.util.UUID; import java.util.function.Function; import java.util.stream.Collectors; +import static org.thingsboard.server.common.data.cf.configuration.PropagationCalculatedFieldConfiguration.PROPAGATION_CONFIG_ARGUMENT; + public class CalculatedFieldUtils { public static CalculatedFieldIdProto toProto(CalculatedFieldId cfId) { @@ -105,6 +110,7 @@ public class CalculatedFieldUtils { case SINGLE_VALUE -> builder.addSingleValueArguments(toSingleValueArgumentProto(argName, (SingleValueArgumentEntry) argEntry)); case TS_ROLLING -> builder.addRollingValueArguments(toRollingArgumentProto(argName, (TsRollingArgumentEntry) argEntry)); case GEOFENCING -> builder.addGeofencingArguments(toGeofencingArgumentProto(argName, (GeofencingArgumentEntry) argEntry)); + case PROPAGATION -> builder.addAllPropagationEntityIds(toPropagationEntityIdsProto((PropagationArgumentEntry) argEntry)); case RELATED_ENTITIES -> { RelatedEntitiesArgumentEntry relatedEntitiesArgumentEntry = (RelatedEntitiesArgumentEntry) argEntry; relatedEntitiesArgumentEntry.getEntityInputs() @@ -133,6 +139,10 @@ public class CalculatedFieldUtils { return builder.build(); } + private static List toPropagationEntityIdsProto(PropagationArgumentEntry argEntry) { + return argEntry.getPropagationEntityIds().stream().map(ProtoUtils::toProto).collect(Collectors.toList()); + } + private static AlarmRuleStateProto toAlarmRuleStateProto(AlarmRuleState ruleState) { return AlarmRuleStateProto.newBuilder() .setSeverity(Optional.ofNullable(ruleState.getSeverity()).map(Enum::name).orElse("")) @@ -269,6 +279,10 @@ public class CalculatedFieldUtils { proto.getGeofencingArgumentsList().forEach(argProto -> state.getArguments().put(argProto.getArgName(), fromGeofencingArgumentProto(argProto))); } + case PROPAGATION -> { + List propagationEntityIds = proto.getPropagationEntityIdsList().stream().map(ProtoUtils::fromProto).toList(); + state.getArguments().put(PROPAGATION_CONFIG_ARGUMENT, new PropagationArgumentEntry(propagationEntityIds)); + } case ALARM -> { AlarmCalculatedFieldState alarmState = (AlarmCalculatedFieldState) state; AlarmStateProto alarmStateProto = proto.getAlarmState(); diff --git a/application/src/test/java/org/thingsboard/server/utils/CalculatedFieldUtilsTest.java b/application/src/test/java/org/thingsboard/server/utils/CalculatedFieldUtilsTest.java index db24e51123..9573c9fa35 100644 --- a/application/src/test/java/org/thingsboard/server/utils/CalculatedFieldUtilsTest.java +++ b/application/src/test/java/org/thingsboard/server/utils/CalculatedFieldUtilsTest.java @@ -119,7 +119,7 @@ class CalculatedFieldUtilsTest { } @Test - void toProtoAndFromProto_shouldCreatePropagationStateWithoutPropagationArgument() { + void toProtoAndFromProto_shouldCreatePropagationStateWithPropagationArgument() { // given CalculatedFieldEntityCtxId stateId = mock(CalculatedFieldEntityCtxId.class); given(stateId.tenantId()).willReturn(TENANT_ID); @@ -158,7 +158,7 @@ class CalculatedFieldUtilsTest { assertThat(propagationState.getEntityId()).isEqualTo(DEVICE_ID); assertThat(propagationState.getArguments()).isNotNull(); - assertThat(propagationState.getArguments().get(PROPAGATION_CONFIG_ARGUMENT)).isNull(); + assertThat(propagationState.getArguments().get(PROPAGATION_CONFIG_ARGUMENT)).isEqualTo(propagationArgumentEntry); assertThat(propagationState.getArguments().get("state")).isNotNull().isEqualTo(singleValueArgumentEntry); assertThat(propagationState.getRequiredArguments()).isNull(); assertThat(propagationState.getReadinessStatus()).isNull(); diff --git a/common/proto/src/main/proto/queue.proto b/common/proto/src/main/proto/queue.proto index 9fb8528bce..3cbc84ba1a 100644 --- a/common/proto/src/main/proto/queue.proto +++ b/common/proto/src/main/proto/queue.proto @@ -935,6 +935,7 @@ message CalculatedFieldStateProto { int64 lastArgsUpdateTs = 7; int64 lastMetricsEvalTs = 8; repeated ArgumentIntervalProto aggregationArguments = 9; + repeated EntityIdProto propagationEntityIds = 10; } //Used to report session state to tb-Service and persist this state in the cache on the tb-Service level. From e36f7d3375ef6af7254c96cdb288d35f7347cb54 Mon Sep 17 00:00:00 2001 From: dshvaika Date: Fri, 5 Dec 2025 11:51:49 +0200 Subject: [PATCH 3/8] additional trace logs for CFs in msa --- msa/black-box-tests/src/test/resources/tb-node/conf/logback.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/msa/black-box-tests/src/test/resources/tb-node/conf/logback.xml b/msa/black-box-tests/src/test/resources/tb-node/conf/logback.xml index aa88f0bbb0..dc1c94bcd2 100644 --- a/msa/black-box-tests/src/test/resources/tb-node/conf/logback.xml +++ b/msa/black-box-tests/src/test/resources/tb-node/conf/logback.xml @@ -49,6 +49,8 @@ + + From 94c2c173de2da4d61ff35f54a808443a6ebd66eb Mon Sep 17 00:00:00 2001 From: dshvaika Date: Fri, 5 Dec 2025 14:08:23 +0200 Subject: [PATCH 4/8] propagation logic for add, remove relations refactoring --- ...CalculatedFieldEntityMessageProcessor.java | 39 ++++---- ...faultCalculatedFieldProcessingService.java | 2 +- .../cf/PropagationCalculatedFieldResult.java | 4 +- .../propagation/PropagationArgumentEntry.java | 51 +++++----- .../PropagationCalculatedFieldState.java | 34 +++---- .../server/utils/CalculatedFieldUtils.java | 24 +---- .../state/PropagationArgumentEntryTest.java | 95 +++++++++++-------- .../PropagationCalculatedFieldStateTest.java | 23 ++--- .../utils/CalculatedFieldUtilsTest.java | 5 +- common/proto/src/main/proto/queue.proto | 1 - 10 files changed, 139 insertions(+), 139 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/actors/calculatedField/CalculatedFieldEntityMessageProcessor.java b/application/src/main/java/org/thingsboard/server/actors/calculatedField/CalculatedFieldEntityMessageProcessor.java index 9d8231956c..209c2d88a0 100644 --- a/application/src/main/java/org/thingsboard/server/actors/calculatedField/CalculatedFieldEntityMessageProcessor.java +++ b/application/src/main/java/org/thingsboard/server/actors/calculatedField/CalculatedFieldEntityMessageProcessor.java @@ -229,26 +229,23 @@ public class CalculatedFieldEntityMessageProcessor extends AbstractContextAwareM var callback = new MultipleTbCallback(CALLBACKS_PER_CF, msg.getCallback()); var state = states.get(ctx.getCfId()); try { + Map updatedArgs = null; if (state == null) { state = createState(ctx); - } - Map updatedArgs = null; - if (state instanceof RelatedEntitiesAggregationCalculatedFieldState relatedEntitiesAggState) { - Map fetchedArgs = cfService.fetchArgsFromDb(tenantId, msg.getRelatedEntityId(), ctx.getArguments()); - updatedArgs = relatedEntitiesAggState.updateEntityData(setEntityIdToSingleEntityArguments(msg.getRelatedEntityId(), fetchedArgs)); - } - if (state instanceof PropagationCalculatedFieldState propagationState) { - PropagationArgumentEntry propagationArgument = propagationState.getPropagationArgument(); - boolean added = propagationArgument.addPropagationEntityId(msg.getRelatedEntityId()); - if (added) { - propagationState.resetReadinessStatus(); - updatedArgs = Map.of(PROPAGATION_CONFIG_ARGUMENT, new PropagationArgumentEntry(List.of(msg.getRelatedEntityId()))); + } else { + if (state instanceof RelatedEntitiesAggregationCalculatedFieldState relatedEntitiesAggState) { + Map fetchedArgs = cfService.fetchArgsFromDb(tenantId, msg.getRelatedEntityId(), ctx.getArguments()); + updatedArgs = relatedEntitiesAggState.updateEntityData(setEntityIdToSingleEntityArguments(msg.getRelatedEntityId(), fetchedArgs)); + } + if (state instanceof PropagationCalculatedFieldState propagationState) { + PropagationArgumentEntry entry = new PropagationArgumentEntry(); + entry.setAdded(msg.getRelatedEntityId()); + updatedArgs = propagationState.update(Map.of(PROPAGATION_CONFIG_ARGUMENT, entry), ctx); + } + if (CollectionsUtil.isEmpty(updatedArgs)) { + msg.getCallback().onSuccess(); + return; } - } - - if (CollectionsUtil.isEmpty(updatedArgs)) { - msg.getCallback().onSuccess(); - return; } state.checkStateSize(new CalculatedFieldEntityCtxId(tenantId, ctx.getCfId(), entityId), ctx.getMaxStateSize()); if (state.isSizeOk()) { @@ -286,11 +283,9 @@ public class CalculatedFieldEntityMessageProcessor extends AbstractContextAwareM return; } if (state instanceof PropagationCalculatedFieldState propagationState) { - PropagationArgumentEntry propagationArgument = propagationState.getPropagationArgument(); - boolean removed = propagationArgument.removePropagationEntityId(msg.getRelatedEntityId()); - if (removed) { - propagationState.resetReadinessStatus(); - } + PropagationArgumentEntry entry = new PropagationArgumentEntry(); + entry.setRemoved(msg.getRelatedEntityId()); + propagationState.update(Map.of(PROPAGATION_CONFIG_ARGUMENT, entry), ctx); } msg.getCallback().onSuccess(); } diff --git a/application/src/main/java/org/thingsboard/server/service/cf/DefaultCalculatedFieldProcessingService.java b/application/src/main/java/org/thingsboard/server/service/cf/DefaultCalculatedFieldProcessingService.java index 818a972251..271fdb828d 100644 --- a/application/src/main/java/org/thingsboard/server/service/cf/DefaultCalculatedFieldProcessingService.java +++ b/application/src/main/java/org/thingsboard/server/service/cf/DefaultCalculatedFieldProcessingService.java @@ -171,7 +171,7 @@ public class DefaultCalculatedFieldProcessingService extends AbstractCalculatedF private void handlePropagationResults(PropagationCalculatedFieldResult propagationResult, TbCallback callback, TriConsumer telemetryResultHandler) { - List propagationEntityIds = propagationResult.getPropagationEntityIds(); + List propagationEntityIds = propagationResult.getEntityIds(); if (propagationEntityIds.isEmpty()) { callback.onSuccess(); return; diff --git a/application/src/main/java/org/thingsboard/server/service/cf/PropagationCalculatedFieldResult.java b/application/src/main/java/org/thingsboard/server/service/cf/PropagationCalculatedFieldResult.java index a6d9e203cb..09ec5b6ed7 100644 --- a/application/src/main/java/org/thingsboard/server/service/cf/PropagationCalculatedFieldResult.java +++ b/application/src/main/java/org/thingsboard/server/service/cf/PropagationCalculatedFieldResult.java @@ -28,7 +28,7 @@ import java.util.List; @Builder public final class PropagationCalculatedFieldResult implements CalculatedFieldResult { - private final List propagationEntityIds; + private final List entityIds; private final TelemetryCalculatedFieldResult result; @Override @@ -43,7 +43,7 @@ public final class PropagationCalculatedFieldResult implements CalculatedFieldRe @Override public boolean isEmpty() { - return CollectionsUtil.isEmpty(propagationEntityIds) || result.isEmpty(); + return CollectionsUtil.isEmpty(entityIds) || result.isEmpty(); } } diff --git a/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/propagation/PropagationArgumentEntry.java b/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/propagation/PropagationArgumentEntry.java index 964aa5487e..0450a0599a 100644 --- a/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/propagation/PropagationArgumentEntry.java +++ b/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/propagation/PropagationArgumentEntry.java @@ -19,22 +19,30 @@ import lombok.Data; import org.thingsboard.script.api.tbel.TbelCfArg; import org.thingsboard.script.api.tbel.TbelCfPropagationArg; import org.thingsboard.server.common.data.id.EntityId; -import org.thingsboard.server.common.data.util.CollectionsUtil; import org.thingsboard.server.service.cf.ctx.state.ArgumentEntry; import org.thingsboard.server.service.cf.ctx.state.ArgumentEntryType; -import java.util.ArrayList; +import java.util.HashSet; import java.util.List; +import java.util.Set; @Data public class PropagationArgumentEntry implements ArgumentEntry { - private List propagationEntityIds; + private Set entityIds; + private transient EntityId added; + private transient EntityId removed; private boolean forceResetPrevious; - public PropagationArgumentEntry(List propagationEntityIds) { - this.propagationEntityIds = new ArrayList<>(propagationEntityIds); + public PropagationArgumentEntry() { + this.entityIds = new HashSet<>(); + this.added = null; + this.removed = null; + } + + public PropagationArgumentEntry(List entityIds) { + this.entityIds = new HashSet<>(entityIds); } @Override @@ -44,7 +52,7 @@ public class PropagationArgumentEntry implements ArgumentEntry { @Override public Object getValue() { - return propagationEntityIds; + return entityIds; } @Override @@ -52,33 +60,32 @@ public class PropagationArgumentEntry implements ArgumentEntry { if (!(entry instanceof PropagationArgumentEntry propagationArgumentEntry)) { throw new IllegalArgumentException("Unsupported argument entry type for propagation argument entry: " + entry.getType()); } + if (propagationArgumentEntry.getAdded() != null) { + boolean updated = entityIds.add(propagationArgumentEntry.getAdded()); + if (updated) { + added = propagationArgumentEntry.getAdded(); + } + return updated; + } + if (propagationArgumentEntry.getRemoved() != null) { + return entityIds.remove(propagationArgumentEntry.getRemoved()); + } if (propagationArgumentEntry.isEmpty()) { - propagationEntityIds.clear(); - } else { - propagationEntityIds = propagationArgumentEntry.getPropagationEntityIds(); + entityIds.clear(); + return true; } + entityIds = propagationArgumentEntry.getEntityIds(); return true; } @Override public boolean isEmpty() { - return CollectionsUtil.isEmpty(propagationEntityIds); + return entityIds.isEmpty(); } @Override public TbelCfArg toTbelCfArg() { - return new TbelCfPropagationArg(propagationEntityIds); - } - - public boolean addPropagationEntityId(EntityId propagationEntityId) { - if (propagationEntityIds.contains(propagationEntityId)) { - return false; - } - return propagationEntityIds.add(propagationEntityId); - } - - public boolean removePropagationEntityId(EntityId relatedEntityId) { - return propagationEntityIds.remove(relatedEntityId); + return new TbelCfPropagationArg(entityIds); } } diff --git a/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/propagation/PropagationCalculatedFieldState.java b/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/propagation/PropagationCalculatedFieldState.java index a6abeb1b32..7a182d0a84 100644 --- a/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/propagation/PropagationCalculatedFieldState.java +++ b/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/propagation/PropagationCalculatedFieldState.java @@ -25,7 +25,6 @@ import org.thingsboard.server.common.data.cf.CalculatedFieldType; import org.thingsboard.server.common.data.cf.configuration.Output; import org.thingsboard.server.common.data.cf.configuration.OutputType; import org.thingsboard.server.common.data.id.EntityId; -import org.thingsboard.server.common.data.util.CollectionsUtil; import org.thingsboard.server.service.cf.CalculatedFieldResult; import org.thingsboard.server.service.cf.PropagationCalculatedFieldResult; import org.thingsboard.server.service.cf.TelemetryCalculatedFieldResult; @@ -37,6 +36,7 @@ import org.thingsboard.server.service.cf.ctx.state.SingleValueArgumentEntry; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.Set; import static org.thingsboard.server.common.data.cf.configuration.PropagationCalculatedFieldConfiguration.PROPAGATION_CONFIG_ARGUMENT; @@ -65,26 +65,30 @@ public class PropagationCalculatedFieldState extends ScriptCalculatedFieldState @Override public ListenableFuture performCalculation(Map updatedArgs, CalculatedFieldCtx ctx) { - List propagationEntityIds; - if (CollectionsUtil.isNotEmpty(updatedArgs) && updatedArgs.size() == 1 && updatedArgs.containsKey(PROPAGATION_CONFIG_ARGUMENT)) { - propagationEntityIds = ((PropagationArgumentEntry) updatedArgs.get(PROPAGATION_CONFIG_ARGUMENT)).getPropagationEntityIds(); - } else { - PropagationArgumentEntry propagationArgumentEntry = (PropagationArgumentEntry) arguments.get(PROPAGATION_CONFIG_ARGUMENT); - propagationEntityIds = propagationArgumentEntry.getPropagationEntityIds(); - } - if (propagationEntityIds.isEmpty()) { + ArgumentEntry argumentEntry = arguments.get(PROPAGATION_CONFIG_ARGUMENT); + if (!(argumentEntry instanceof PropagationArgumentEntry propagationArgumentEntry)) { return Futures.immediateFuture(PropagationCalculatedFieldResult.builder().build()); } + List entityIds; + if (propagationArgumentEntry.getAdded() != null) { + entityIds = List.of(propagationArgumentEntry.getAdded()); + propagationArgumentEntry.setAdded(null); + } else { + entityIds = List.copyOf(propagationArgumentEntry.getEntityIds()); + if (entityIds.isEmpty()) { + return Futures.immediateFuture(PropagationCalculatedFieldResult.builder().build()); + } + } if (ctx.isApplyExpressionForResolvedArguments()) { return Futures.transform(super.performCalculation(updatedArgs, ctx), telemetryCfResult -> PropagationCalculatedFieldResult.builder() - .propagationEntityIds(propagationEntityIds) + .entityIds(entityIds) .result((TelemetryCalculatedFieldResult) telemetryCfResult) .build(), MoreExecutors.directExecutor()); } return Futures.immediateFuture(PropagationCalculatedFieldResult.builder() - .propagationEntityIds(propagationEntityIds) + .entityIds(entityIds) .result(toTelemetryResult(ctx)) .build()); } @@ -113,12 +117,4 @@ public class PropagationCalculatedFieldState extends ScriptCalculatedFieldState return telemetryCfBuilder.build(); } - public PropagationArgumentEntry getPropagationArgument() { - return (PropagationArgumentEntry) arguments.get(PROPAGATION_CONFIG_ARGUMENT); - } - - public void resetReadinessStatus() { - readinessStatus = checkReadiness(requiredArguments, arguments); - } - } diff --git a/application/src/main/java/org/thingsboard/server/utils/CalculatedFieldUtils.java b/application/src/main/java/org/thingsboard/server/utils/CalculatedFieldUtils.java index 5fd48398e4..7046af3d9c 100644 --- a/application/src/main/java/org/thingsboard/server/utils/CalculatedFieldUtils.java +++ b/application/src/main/java/org/thingsboard/server/utils/CalculatedFieldUtils.java @@ -33,7 +33,6 @@ import org.thingsboard.server.gen.transport.TransportProtos.ArgumentIntervalProt import org.thingsboard.server.gen.transport.TransportProtos.CalculatedFieldEntityCtxIdProto; import org.thingsboard.server.gen.transport.TransportProtos.CalculatedFieldIdProto; import org.thingsboard.server.gen.transport.TransportProtos.CalculatedFieldStateProto; -import org.thingsboard.server.gen.transport.TransportProtos.EntityIdProto; import org.thingsboard.server.gen.transport.TransportProtos.GeofencingArgumentProto; import org.thingsboard.server.gen.transport.TransportProtos.GeofencingZoneProto; import org.thingsboard.server.gen.transport.TransportProtos.SingleValueArgumentProto; @@ -62,7 +61,6 @@ import org.thingsboard.server.service.cf.ctx.state.propagation.PropagationArgume import org.thingsboard.server.service.cf.ctx.state.propagation.PropagationCalculatedFieldState; import java.util.HashMap; -import java.util.List; import java.util.Map; import java.util.Optional; import java.util.TreeMap; @@ -110,7 +108,6 @@ public class CalculatedFieldUtils { case SINGLE_VALUE -> builder.addSingleValueArguments(toSingleValueArgumentProto(argName, (SingleValueArgumentEntry) argEntry)); case TS_ROLLING -> builder.addRollingValueArguments(toRollingArgumentProto(argName, (TsRollingArgumentEntry) argEntry)); case GEOFENCING -> builder.addGeofencingArguments(toGeofencingArgumentProto(argName, (GeofencingArgumentEntry) argEntry)); - case PROPAGATION -> builder.addAllPropagationEntityIds(toPropagationEntityIdsProto((PropagationArgumentEntry) argEntry)); case RELATED_ENTITIES -> { RelatedEntitiesArgumentEntry relatedEntitiesArgumentEntry = (RelatedEntitiesArgumentEntry) argEntry; relatedEntitiesArgumentEntry.getEntityInputs() @@ -139,10 +136,6 @@ public class CalculatedFieldUtils { return builder.build(); } - private static List toPropagationEntityIdsProto(PropagationArgumentEntry argEntry) { - return argEntry.getPropagationEntityIds().stream().map(ProtoUtils::toProto).collect(Collectors.toList()); - } - private static AlarmRuleStateProto toAlarmRuleStateProto(AlarmRuleState ruleState) { return AlarmRuleStateProto.newBuilder() .setSeverity(Optional.ofNullable(ruleState.getSeverity()).map(Enum::name).orElse("")) @@ -271,18 +264,11 @@ public class CalculatedFieldUtils { state.getArguments().put(argProto.getArgName(), fromSingleValueArgumentProto(argProto))); switch (type) { - case SCRIPT -> { - proto.getRollingValueArgumentsList().forEach(argProto -> - state.getArguments().put(argProto.getKey(), fromRollingArgumentProto(argProto))); - } - case GEOFENCING -> { - proto.getGeofencingArgumentsList().forEach(argProto -> - state.getArguments().put(argProto.getArgName(), fromGeofencingArgumentProto(argProto))); - } - case PROPAGATION -> { - List propagationEntityIds = proto.getPropagationEntityIdsList().stream().map(ProtoUtils::fromProto).toList(); - state.getArguments().put(PROPAGATION_CONFIG_ARGUMENT, new PropagationArgumentEntry(propagationEntityIds)); - } + case SCRIPT -> proto.getRollingValueArgumentsList().forEach(argProto -> + state.getArguments().put(argProto.getKey(), fromRollingArgumentProto(argProto))); + case GEOFENCING -> proto.getGeofencingArgumentsList().forEach(argProto -> + state.getArguments().put(argProto.getArgName(), fromGeofencingArgumentProto(argProto))); + case PROPAGATION -> state.getArguments().put(PROPAGATION_CONFIG_ARGUMENT, new PropagationArgumentEntry()); case ALARM -> { AlarmCalculatedFieldState alarmState = (AlarmCalculatedFieldState) state; AlarmStateProto alarmStateProto = proto.getAlarmState(); diff --git a/application/src/test/java/org/thingsboard/server/service/cf/ctx/state/PropagationArgumentEntryTest.java b/application/src/test/java/org/thingsboard/server/service/cf/ctx/state/PropagationArgumentEntryTest.java index 32e31e7a9e..bf6a112e72 100644 --- a/application/src/test/java/org/thingsboard/server/service/cf/ctx/state/PropagationArgumentEntryTest.java +++ b/application/src/test/java/org/thingsboard/server/service/cf/ctx/state/PropagationArgumentEntryTest.java @@ -25,6 +25,7 @@ import org.thingsboard.server.service.cf.ctx.state.propagation.PropagationArgume import java.util.ArrayList; import java.util.List; +import java.util.Set; import java.util.UUID; import static org.assertj.core.api.Assertions.assertThat; @@ -59,10 +60,10 @@ public class PropagationArgumentEntryTest { @Test void testGetValueReturnsPropagationIds() { - assertThat(entry.getValue()).isInstanceOf(List.class); + assertThat(entry.getValue()).isInstanceOf(Set.class); @SuppressWarnings("unchecked") - List value = (List) entry.getValue(); - assertThat(value).containsExactly(ENTITY_1_ID, ENTITY_2_ID); + Set value = (Set) entry.getValue(); + assertThat(value).containsExactlyInAnyOrder(ENTITY_1_ID, ENTITY_2_ID); } @Test @@ -87,7 +88,7 @@ public class PropagationArgumentEntryTest { boolean changed = entry.updateEntry(updated); assertThat(changed).isTrue(); - assertThat(entry.getPropagationEntityIds()).containsExactlyElementsOf(newIds); + assertThat(entry.getEntityIds()).containsExactlyElementsOf(newIds); } @Test @@ -97,59 +98,79 @@ public class PropagationArgumentEntryTest { boolean changed = entry.updateEntry(updatedEmpty); assertThat(changed).isTrue(); - assertThat(entry.getPropagationEntityIds()).isEmpty(); + assertThat(entry.getEntityIds()).isEmpty(); } @Test - @SuppressWarnings("unchecked") - void testToTbelCfArgWithValues() { - TbelCfArg arg = entry.toTbelCfArg(); - assertThat(arg).isInstanceOf(TbelCfPropagationArg.class); + void testUpdateEntryWhenAdded() { + var added = new PropagationArgumentEntry(); + added.setAdded(ENTITY_3_ID); - TbelCfPropagationArg tbelCfPropagationArg = (TbelCfPropagationArg) arg; - assertThat(tbelCfPropagationArg.getValue()).isInstanceOf(List.class); - assertThat((List) tbelCfPropagationArg.getValue()).containsExactly(ENTITY_1_ID, ENTITY_2_ID); - } + boolean changed = entry.updateEntry(added); + assertThat(changed).isTrue(); + assertThat(entry.getEntityIds()).containsExactlyInAnyOrder(ENTITY_1_ID, ENTITY_2_ID, ENTITY_3_ID); + assertThat(entry.getAdded()).isEqualTo(ENTITY_3_ID); + } @Test - @SuppressWarnings("unchecked") - void testToTbelCfArgWithEmptyValues() { - var empty = new PropagationArgumentEntry(List.of()); - TbelCfArg emptyArg = empty.toTbelCfArg(); - assertThat(emptyArg).isInstanceOf(TbelCfPropagationArg.class); + void testUpdateEntryWhenAddedExistingEntity() { + var added = new PropagationArgumentEntry(); + added.setAdded(ENTITY_2_ID); - TbelCfPropagationArg tbelCfPropagationArg = (TbelCfPropagationArg) emptyArg; - assertThat(tbelCfPropagationArg.getValue()).isInstanceOf(List.class); - assertThat((List) tbelCfPropagationArg.getValue()).isEmpty(); + boolean changed = entry.updateEntry(added); + + assertThat(changed).isFalse(); + assertThat(entry.getEntityIds()).containsExactlyInAnyOrder(ENTITY_1_ID, ENTITY_2_ID); + assertThat(entry.getAdded()).isNull(); } @Test - void testAddNewPropagationEntityIdToEmptyArgument() { - PropagationArgumentEntry empty = new PropagationArgumentEntry(List.of()); - assertThat(empty.addPropagationEntityId(ENTITY_1_ID)).isTrue(); - assertThat(empty.getPropagationEntityIds()).containsExactly(ENTITY_1_ID); + void testUpdateEntryWhenRemoved() { + var removed = new PropagationArgumentEntry(); + removed.setRemoved(ENTITY_2_ID); + + boolean changed = entry.updateEntry(removed); + + assertThat(changed).isTrue(); + assertThat(entry.getEntityIds()).containsExactlyInAnyOrder(ENTITY_1_ID); + assertThat(entry.getRemoved()).isNull(); } @Test - void testAddNewPropagationEntityIdThatAlreadyExists() { - PropagationArgumentEntry hasEntity = new PropagationArgumentEntry(List.of(ENTITY_1_ID)); - assertThat(hasEntity.addPropagationEntityId(ENTITY_1_ID)).isFalse(); - assertThat(hasEntity.getPropagationEntityIds()).containsExactly(ENTITY_1_ID); + void testUpdateEntryWhenRemovedNonExistingEntity() { + var removed = new PropagationArgumentEntry(); + removed.setRemoved(ENTITY_3_ID); + + boolean changed = entry.updateEntry(removed); + + assertThat(changed).isFalse(); + assertThat(entry.getEntityIds()).containsExactlyInAnyOrder(ENTITY_1_ID, ENTITY_2_ID); + assertThat(entry.getRemoved()).isNull(); } @Test - void testAddNewPropagationEntityId() { - PropagationArgumentEntry hasEntity = new PropagationArgumentEntry(List.of(ENTITY_1_ID, ENTITY_2_ID)); - assertThat(hasEntity.addPropagationEntityId(ENTITY_3_ID)).isTrue(); - assertThat(hasEntity.getPropagationEntityIds()).contains(ENTITY_1_ID, ENTITY_2_ID, ENTITY_3_ID); + @SuppressWarnings("unchecked") + void testToTbelCfArgWithValues() { + TbelCfArg arg = entry.toTbelCfArg(); + assertThat(arg).isInstanceOf(TbelCfPropagationArg.class); + + TbelCfPropagationArg tbelCfPropagationArg = (TbelCfPropagationArg) arg; + assertThat(tbelCfPropagationArg.getValue()).isInstanceOf(Set.class); + assertThat((Set) tbelCfPropagationArg.getValue()).containsExactlyInAnyOrder(ENTITY_1_ID, ENTITY_2_ID); } + @Test - void testRemovePropagationEntityId() { - PropagationArgumentEntry hasEntity = new PropagationArgumentEntry(List.of(ENTITY_1_ID)); - hasEntity.removePropagationEntityId(ENTITY_1_ID); - assertThat(hasEntity.isEmpty()).isTrue(); + @SuppressWarnings("unchecked") + void testToTbelCfArgWithEmptyValues() { + var empty = new PropagationArgumentEntry(List.of()); + TbelCfArg emptyArg = empty.toTbelCfArg(); + assertThat(emptyArg).isInstanceOf(TbelCfPropagationArg.class); + + TbelCfPropagationArg tbelCfPropagationArg = (TbelCfPropagationArg) emptyArg; + assertThat(tbelCfPropagationArg.getValue()).isInstanceOf(Set.class); + assertThat((Set) tbelCfPropagationArg.getValue()).isEmpty(); } } diff --git a/application/src/test/java/org/thingsboard/server/service/cf/ctx/state/PropagationCalculatedFieldStateTest.java b/application/src/test/java/org/thingsboard/server/service/cf/ctx/state/PropagationCalculatedFieldStateTest.java index 99c8f5631b..add6c1ee39 100644 --- a/application/src/test/java/org/thingsboard/server/service/cf/ctx/state/PropagationCalculatedFieldStateTest.java +++ b/application/src/test/java/org/thingsboard/server/service/cf/ctx/state/PropagationCalculatedFieldStateTest.java @@ -172,7 +172,7 @@ public class PropagationCalculatedFieldStateTest { assertThat(result).isNotNull(); assertThat(result.isEmpty()).isTrue(); - assertThat(result.getPropagationEntityIds()).isNullOrEmpty(); + assertThat(result.getEntityIds()).isNullOrEmpty(); } @Test @@ -185,7 +185,7 @@ public class PropagationCalculatedFieldStateTest { assertThat(propagationResult).isNotNull(); assertThat(propagationResult.isEmpty()).isFalse(); - assertThat(propagationResult.getPropagationEntityIds()).containsExactly(ASSET_ID_2, ASSET_ID_1); + assertThat(propagationResult.getEntityIds()).containsExactly(ASSET_ID_2, ASSET_ID_1); TelemetryCalculatedFieldResult result = propagationResult.getResult(); assertThat(result).isNotNull(); @@ -208,7 +208,7 @@ public class PropagationCalculatedFieldStateTest { assertThat(propagationResult).isNotNull(); assertThat(propagationResult.isEmpty()).isFalse(); - assertThat(propagationResult.getPropagationEntityIds()).containsExactly(ASSET_ID_2, ASSET_ID_1); + assertThat(propagationResult.getEntityIds()).containsExactly(ASSET_ID_2, ASSET_ID_1); TelemetryCalculatedFieldResult result = propagationResult.getResult(); assertThat(result).isNotNull(); @@ -227,20 +227,15 @@ public class PropagationCalculatedFieldStateTest { state.getArguments().put(PROPAGATION_CONFIG_ARGUMENT, propagationArgEntry); state.getArguments().put(TEMPERATURE_ARGUMENT_NAME, singleValueArgEntry); - PropagationArgumentEntry propagationArgument = state.getPropagationArgument(); - assertThat(propagationArgument).isNotNull().isEqualTo(propagationArgEntry); - AssetId newEntityId = new AssetId(UUID.fromString("83e2c962-eeae-4708-984e-e6a24760f9c3")); - boolean added = propagationArgument.addPropagationEntityId(newEntityId); - assertThat(added).isTrue(); - - ArgumentEntry argumentEntry = state.getArguments().get(PROPAGATION_CONFIG_ARGUMENT); - assertThat(argumentEntry).isNotNull().isInstanceOf(PropagationArgumentEntry.class); - assertThat(((PropagationArgumentEntry) argumentEntry).getPropagationEntityIds()).containsExactly(ASSET_ID_2, ASSET_ID_1, newEntityId); + PropagationArgumentEntry propagationArgumentEntry = new PropagationArgumentEntry(); + propagationArgumentEntry.setAdded(newEntityId); + Map updated = state.update(Map.of(PROPAGATION_CONFIG_ARGUMENT, propagationArgumentEntry), ctx); + assertThat(updated).isNotNull().containsEntry(PROPAGATION_CONFIG_ARGUMENT, propagationArgumentEntry); - PropagationCalculatedFieldResult propagationCalculatedFieldResult = performCalculation(Map.of(PROPAGATION_CONFIG_ARGUMENT, new PropagationArgumentEntry(List.of(newEntityId)))); + PropagationCalculatedFieldResult propagationCalculatedFieldResult = performCalculation(updated); assertThat(propagationCalculatedFieldResult).isNotNull(); - assertThat(propagationCalculatedFieldResult.getPropagationEntityIds()).isNotNull().containsExactly(newEntityId); + assertThat(propagationCalculatedFieldResult.getEntityIds()).isNotNull().containsExactly(newEntityId); } private CalculatedField getCalculatedField(boolean applyExpressionToResolvedArguments) { diff --git a/application/src/test/java/org/thingsboard/server/utils/CalculatedFieldUtilsTest.java b/application/src/test/java/org/thingsboard/server/utils/CalculatedFieldUtilsTest.java index 9573c9fa35..83538fe07c 100644 --- a/application/src/test/java/org/thingsboard/server/utils/CalculatedFieldUtilsTest.java +++ b/application/src/test/java/org/thingsboard/server/utils/CalculatedFieldUtilsTest.java @@ -119,7 +119,7 @@ class CalculatedFieldUtilsTest { } @Test - void toProtoAndFromProto_shouldCreatePropagationStateWithPropagationArgument() { + void toProtoAndFromProto_shouldCreatePropagationStateWithEmptyPropagationArgument() { // given CalculatedFieldEntityCtxId stateId = mock(CalculatedFieldEntityCtxId.class); given(stateId.tenantId()).willReturn(TENANT_ID); @@ -158,7 +158,8 @@ class CalculatedFieldUtilsTest { assertThat(propagationState.getEntityId()).isEqualTo(DEVICE_ID); assertThat(propagationState.getArguments()).isNotNull(); - assertThat(propagationState.getArguments().get(PROPAGATION_CONFIG_ARGUMENT)).isEqualTo(propagationArgumentEntry); + assertThat(propagationState.getArguments().get(PROPAGATION_CONFIG_ARGUMENT)).isNotNull(); + assertThat(propagationState.getArguments().get(PROPAGATION_CONFIG_ARGUMENT).isEmpty()).isTrue(); assertThat(propagationState.getArguments().get("state")).isNotNull().isEqualTo(singleValueArgumentEntry); assertThat(propagationState.getRequiredArguments()).isNull(); assertThat(propagationState.getReadinessStatus()).isNull(); diff --git a/common/proto/src/main/proto/queue.proto b/common/proto/src/main/proto/queue.proto index 3cbc84ba1a..9fb8528bce 100644 --- a/common/proto/src/main/proto/queue.proto +++ b/common/proto/src/main/proto/queue.proto @@ -935,7 +935,6 @@ message CalculatedFieldStateProto { int64 lastArgsUpdateTs = 7; int64 lastMetricsEvalTs = 8; repeated ArgumentIntervalProto aggregationArguments = 9; - repeated EntityIdProto propagationEntityIds = 10; } //Used to report session state to tb-Service and persist this state in the cache on the tb-Service level. From a470cf6523a812ce4392ae8fc67b037c35359b9d Mon Sep 17 00:00:00 2001 From: dshvaika Date: Fri, 5 Dec 2025 15:54:06 +0200 Subject: [PATCH 5/8] Fixed incorrect number of callbacks --- .../CalculatedFieldEntityMessageProcessor.java | 5 ++--- .../state/propagation/PropagationCalculatedFieldState.java | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/actors/calculatedField/CalculatedFieldEntityMessageProcessor.java b/application/src/main/java/org/thingsboard/server/actors/calculatedField/CalculatedFieldEntityMessageProcessor.java index 209c2d88a0..55635e9f9d 100644 --- a/application/src/main/java/org/thingsboard/server/actors/calculatedField/CalculatedFieldEntityMessageProcessor.java +++ b/application/src/main/java/org/thingsboard/server/actors/calculatedField/CalculatedFieldEntityMessageProcessor.java @@ -226,7 +226,6 @@ public class CalculatedFieldEntityMessageProcessor extends AbstractContextAwareM private void handleRelationUpdate(CalculatedFieldRelationActionMsg msg) throws CalculatedFieldException { CalculatedFieldCtx ctx = msg.getCalculatedField(); - var callback = new MultipleTbCallback(CALLBACKS_PER_CF, msg.getCallback()); var state = states.get(ctx.getCfId()); try { Map updatedArgs = null; @@ -246,10 +245,10 @@ public class CalculatedFieldEntityMessageProcessor extends AbstractContextAwareM msg.getCallback().onSuccess(); return; } + state.checkStateSize(new CalculatedFieldEntityCtxId(tenantId, ctx.getCfId(), entityId), ctx.getMaxStateSize()); } - state.checkStateSize(new CalculatedFieldEntityCtxId(tenantId, ctx.getCfId(), entityId), ctx.getMaxStateSize()); if (state.isSizeOk()) { - processStateIfReady(state, updatedArgs, ctx, Collections.singletonList(ctx.getCfId()), null, null, callback); + processStateIfReady(state, updatedArgs, ctx, Collections.singletonList(ctx.getCfId()), null, null, msg.getCallback()); } else { throw CalculatedFieldException.builder().ctx(ctx).eventEntity(entityId).errorMessage(ctx.getSizeExceedsLimitMessage()).build(); } diff --git a/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/propagation/PropagationCalculatedFieldState.java b/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/propagation/PropagationCalculatedFieldState.java index 7a182d0a84..5a7753c86a 100644 --- a/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/propagation/PropagationCalculatedFieldState.java +++ b/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/propagation/PropagationCalculatedFieldState.java @@ -36,7 +36,6 @@ import org.thingsboard.server.service.cf.ctx.state.SingleValueArgumentEntry; import java.util.ArrayList; import java.util.List; import java.util.Map; -import java.util.Set; import static org.thingsboard.server.common.data.cf.configuration.PropagationCalculatedFieldConfiguration.PROPAGATION_CONFIG_ARGUMENT; @@ -74,10 +73,10 @@ public class PropagationCalculatedFieldState extends ScriptCalculatedFieldState entityIds = List.of(propagationArgumentEntry.getAdded()); propagationArgumentEntry.setAdded(null); } else { - entityIds = List.copyOf(propagationArgumentEntry.getEntityIds()); - if (entityIds.isEmpty()) { + if (propagationArgumentEntry.getEntityIds().isEmpty()) { return Futures.immediateFuture(PropagationCalculatedFieldResult.builder().build()); } + entityIds = List.copyOf(propagationArgumentEntry.getEntityIds()); } if (ctx.isApplyExpressionForResolvedArguments()) { return Futures.transform(super.performCalculation(updatedArgs, ctx), telemetryCfResult -> From fab611bb211303ef8c2f96b3374a084523208c99 Mon Sep 17 00:00:00 2001 From: dshvaika Date: Fri, 5 Dec 2025 19:41:43 +0200 Subject: [PATCH 6/8] Added trace level for cluster service & rule engine consumer manager --- msa/black-box-tests/src/test/resources/tb-node/conf/logback.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/msa/black-box-tests/src/test/resources/tb-node/conf/logback.xml b/msa/black-box-tests/src/test/resources/tb-node/conf/logback.xml index dc1c94bcd2..9c27ebb2a3 100644 --- a/msa/black-box-tests/src/test/resources/tb-node/conf/logback.xml +++ b/msa/black-box-tests/src/test/resources/tb-node/conf/logback.xml @@ -48,6 +48,7 @@ + From c2ce03c8c6a10369cd9cb4b33fc59843b136d130 Mon Sep 17 00:00:00 2001 From: dshvaika Date: Fri, 5 Dec 2025 19:42:01 +0200 Subject: [PATCH 7/8] Added trace level for cluster service & rule engine consumer manager --- msa/black-box-tests/src/test/resources/tb-node/conf/logback.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/msa/black-box-tests/src/test/resources/tb-node/conf/logback.xml b/msa/black-box-tests/src/test/resources/tb-node/conf/logback.xml index 9c27ebb2a3..f9fd25d44a 100644 --- a/msa/black-box-tests/src/test/resources/tb-node/conf/logback.xml +++ b/msa/black-box-tests/src/test/resources/tb-node/conf/logback.xml @@ -49,6 +49,7 @@ + From f379c354c56921720c1189d01fd1aae125711fe4 Mon Sep 17 00:00:00 2001 From: dshvaika Date: Mon, 8 Dec 2025 19:10:42 +0200 Subject: [PATCH 8/8] rollback logback changes for black-box tests --- .../src/test/resources/tb-node/conf/logback.xml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/msa/black-box-tests/src/test/resources/tb-node/conf/logback.xml b/msa/black-box-tests/src/test/resources/tb-node/conf/logback.xml index f9fd25d44a..aa88f0bbb0 100644 --- a/msa/black-box-tests/src/test/resources/tb-node/conf/logback.xml +++ b/msa/black-box-tests/src/test/resources/tb-node/conf/logback.xml @@ -48,11 +48,7 @@ - - - -