Commit 3eaae1ef32cf601ca06001e95a5f5f130c4d74a8

Authored by Andrii Shvaika
1 parent ff3fd89a

Statistics Implementation

Showing 64 changed files with 976 additions and 720 deletions
... ... @@ -24,10 +24,9 @@ import akka.actor.Terminated;
24 24 import com.google.common.collect.BiMap;
25 25 import com.google.common.collect.HashBiMap;
26 26 import org.thingsboard.server.actors.ActorSystemContext;
27   -import org.thingsboard.server.actors.ruleChain.RuleChainManagerActor;
  27 +import org.thingsboard.server.actors.service.ContextAwareActor;
28 28 import org.thingsboard.server.actors.service.ContextBasedCreator;
29 29 import org.thingsboard.server.actors.service.DefaultActorService;
30   -import org.thingsboard.server.actors.shared.rulechain.SystemRuleChainManager;
31 30 import org.thingsboard.server.actors.tenant.TenantActor;
32 31 import org.thingsboard.server.common.data.EntityType;
33 32 import org.thingsboard.server.common.data.Tenant;
... ... @@ -37,16 +36,14 @@ import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
37 36 import org.thingsboard.server.common.msg.MsgType;
38 37 import org.thingsboard.server.common.msg.TbActorMsg;
39 38 import org.thingsboard.server.common.msg.aware.TenantAwareMsg;
40   -import org.thingsboard.server.common.msg.cluster.SendToClusterMsg;
41 39 import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg;
42   -import org.thingsboard.server.common.msg.queue.PartitionChangeMsg;
43 40 import org.thingsboard.server.common.msg.queue.QueueToRuleEngineMsg;
44   -import org.thingsboard.server.common.msg.queue.ServiceType;
  41 +import org.thingsboard.server.common.msg.queue.RuleEngineException;
45 42 import org.thingsboard.server.dao.model.ModelConstants;
46 43 import org.thingsboard.server.dao.tenant.TenantService;
47 44 import scala.concurrent.duration.Duration;
48 45
49   -public class AppActor extends RuleChainManagerActor {
  46 +public class AppActor extends ContextAwareActor {
50 47
51 48 private static final TenantId SYSTEM_TENANT = new TenantId(ModelConstants.NULL_UUID);
52 49 private final TenantService tenantService;
... ... @@ -54,7 +51,7 @@ public class AppActor extends RuleChainManagerActor {
54 51 private boolean ruleChainsInitialized;
55 52
56 53 private AppActor(ActorSystemContext systemContext) {
57   - super(systemContext, new SystemRuleChainManager(systemContext));
  54 + super(systemContext);
58 55 this.tenantService = systemContext.getTenantService();
59 56 this.tenantActors = HashBiMap.create();
60 57 }
... ... @@ -80,9 +77,6 @@ public class AppActor extends RuleChainManagerActor {
80 77 switch (msg.getMsgType()) {
81 78 case APP_INIT_MSG:
82 79 break;
83   - case SEND_TO_CLUSTER_MSG:
84   - onPossibleClusterMsg((SendToClusterMsg) msg);
85   - break;
86 80 case PARTITION_CHANGE_MSG:
87 81 broadcast(msg);
88 82 break;
... ... @@ -98,7 +92,6 @@ public class AppActor extends RuleChainManagerActor {
98 92 case DEVICE_NAME_OR_TYPE_UPDATE_TO_DEVICE_ACTOR_MSG:
99 93 case DEVICE_RPC_REQUEST_TO_DEVICE_ACTOR_MSG:
100 94 case SERVER_RPC_RESPONSE_TO_DEVICE_ACTOR_MSG:
101   - case REMOTE_TO_RULE_CHAIN_TELL_NEXT_MSG:
102 95 onToDeviceActorMsg((TenantAwareMsg) msg);
103 96 break;
104 97 default:
... ... @@ -110,7 +103,6 @@ public class AppActor extends RuleChainManagerActor {
110 103 private void initRuleChainsAndTenantActors() {
111 104 log.info("Starting main system actor.");
112 105 try {
113   - initRuleChains();
114 106 if (systemContext.isTenantComponentsInitEnabled()) {
115 107 PageDataIterable<Tenant> tenantIterator = new PageDataIterable<>(tenantService::findTenants, ENTITY_PACK_LIMIT);
116 108 for (Tenant tenant : tenantIterator) {
... ... @@ -125,37 +117,22 @@ public class AppActor extends RuleChainManagerActor {
125 117 }
126 118 }
127 119
128   - private void onPossibleClusterMsg(SendToClusterMsg msg) {
129   - //TODO 2.5
130   -// Optional<ServerAddress> address = systemContext.getRoutingService().resolveById(msg.getEntityId());
131   -// if (address.isPresent()) {
132   -
133   -// systemContext.getRpcService().tell(
134   -// systemContext.getEncodingService().convertToProtoDataMessage(address.get(), msg.getMsg()));
135   -// } else {
136   - self().tell(msg.getMsg(), ActorRef.noSender());
137   -// }
138   - }
139   -
140 120 private void onQueueToRuleEngineMsg(QueueToRuleEngineMsg msg) {
141 121 if (SYSTEM_TENANT.equals(msg.getTenantId())) {
142   -// this may be a notification about system entities created.
143   -// log.warn("[{}] Invalid service to rule engine msg called. System messages are not supported yet: {}", SYSTEM_TENANT, msg);
  122 + msg.getTbMsg().getCallback().onFailure(new RuleEngineException("Message has system tenant id!"));
144 123 } else {
145 124 getOrCreateTenantActor(msg.getTenantId()).tell(msg, self());
146 125 }
147 126 }
148 127
149   - @Override
150 128 protected void broadcast(Object msg) {
151   - super.broadcast(msg);
152 129 tenantActors.values().forEach(actorRef -> actorRef.tell(msg, ActorRef.noSender()));
153 130 }
154 131
155 132 private void onComponentLifecycleMsg(ComponentLifecycleMsg msg) {
156 133 ActorRef target = null;
157 134 if (SYSTEM_TENANT.equals(msg.getTenantId())) {
158   - target = getEntityActorRef(msg.getEntityId());
  135 + log.warn("Message has system tenant id: {}", msg);
159 136 } else {
160 137 if (msg.getEntityId().getEntityType() == EntityType.TENANT
161 138 && msg.getEvent() == ComponentLifecycleEvent.DELETED) {
... ...
... ... @@ -56,7 +56,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.ToDeviceRpcRequestMs
56 56 import org.thingsboard.server.gen.transport.TransportProtos.ToDeviceRpcResponseMsg;
57 57 import org.thingsboard.server.gen.transport.TransportProtos.TransportToDeviceActorMsg;
58 58 import org.thingsboard.server.gen.transport.TransportProtos.TsKvProto;
59   -import org.thingsboard.server.common.msg.queue.TbMsgCallback;
  59 +import org.thingsboard.server.common.msg.queue.TbCallback;
60 60 import org.thingsboard.server.service.rpc.FromDeviceRpcResponse;
61 61 import org.thingsboard.server.service.rpc.ToDeviceRpcRequestActorMsg;
62 62 import org.thingsboard.server.service.rpc.ToServerRpcResponseActorMsg;
... ... @@ -213,7 +213,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor {
213 213
214 214 void process(ActorContext context, TransportToDeviceActorMsgWrapper wrapper) {
215 215 TransportToDeviceActorMsg msg = wrapper.getMsg();
216   - TbMsgCallback callback = wrapper.getCallback();
  216 + TbCallback callback = wrapper.getCallback();
217 217 if (msg.hasSessionEvent()) {
218 218 processSessionStateMsgs(msg.getSessionInfo(), msg.getSessionEvent());
219 219 }
... ...
... ... @@ -5,7 +5,7 @@
5 5 * you may not use this file except in compliance with the License.
6 6 * You may obtain a copy of the License at
7 7 *
8   - * http://www.apache.org/licenses/LICENSE-2.0
  8 + * http://www.apache.org/licenses/LICENSE-2.0
9 9 *
10 10 * Unless required by applicable law or agreed to in writing, software
11 11 * distributed under the License is distributed on an "AS IS" BASIS,
... ... @@ -110,7 +110,7 @@ class DefaultTbContext implements TbContext {
110 110 if (nodeCtx.getSelf().isDebugMode()) {
111 111 relationTypes.forEach(relationType -> mainCtx.persistDebugOutput(nodeCtx.getTenantId(), nodeCtx.getSelf().getId(), msg, relationType, th));
112 112 }
113   - nodeCtx.getChainActor().tell(new RuleNodeToRuleChainTellNextMsg(nodeCtx.getSelf().getId(), relationTypes, msg), nodeCtx.getSelfActor());
  113 + nodeCtx.getChainActor().tell(new RuleNodeToRuleChainTellNextMsg(nodeCtx.getSelf().getId(), relationTypes, msg, th != null ? th.getMessage() : null), nodeCtx.getSelfActor());
114 114 }
115 115
116 116 @Override
... ... @@ -140,52 +140,60 @@ class DefaultTbContext implements TbContext {
140 140 }
141 141
142 142 @Override
  143 + public void enqueueForTellFailure(TbMsg tbMsg, String failureMessage) {
  144 + TopicPartitionInfo tpi = mainCtx.resolve(ServiceType.TB_RULE_ENGINE, getTenantId(), tbMsg.getOriginator());
  145 + enqueueForTellNext(tpi, tbMsg, Collections.singleton(TbRelationTypes.FAILURE), failureMessage, null, null);
  146 + }
  147 +
  148 + @Override
143 149 public void enqueueForTellNext(TbMsg tbMsg, String relationType) {
144 150 TopicPartitionInfo tpi = mainCtx.resolve(ServiceType.TB_RULE_ENGINE, getTenantId(), tbMsg.getOriginator());
145   - enqueueForTellNext(tpi, tbMsg, Collections.singleton(relationType), null, null);
  151 + enqueueForTellNext(tpi, tbMsg, Collections.singleton(relationType), null, null, null);
146 152 }
147 153
148 154 @Override
149 155 public void enqueueForTellNext(TbMsg tbMsg, Set<String> relationTypes) {
150 156 TopicPartitionInfo tpi = mainCtx.resolve(ServiceType.TB_RULE_ENGINE, getTenantId(), tbMsg.getOriginator());
151   - enqueueForTellNext(tpi, tbMsg, relationTypes, null, null);
  157 + enqueueForTellNext(tpi, tbMsg, relationTypes, null, null, null);
152 158 }
153 159
154 160 @Override
155 161 public void enqueueForTellNext(TbMsg tbMsg, String relationType, Runnable onSuccess, Consumer<Throwable> onFailure) {
156 162 TopicPartitionInfo tpi = mainCtx.resolve(ServiceType.TB_RULE_ENGINE, getTenantId(), tbMsg.getOriginator());
157   - enqueueForTellNext(tpi, tbMsg, Collections.singleton(relationType), onSuccess, onFailure);
  163 + enqueueForTellNext(tpi, tbMsg, Collections.singleton(relationType), null, onSuccess, onFailure);
158 164 }
159 165
160 166 @Override
161 167 public void enqueueForTellNext(TbMsg tbMsg, Set<String> relationTypes, Runnable onSuccess, Consumer<Throwable> onFailure) {
162 168 TopicPartitionInfo tpi = mainCtx.resolve(ServiceType.TB_RULE_ENGINE, getTenantId(), tbMsg.getOriginator());
163   - enqueueForTellNext(tpi, tbMsg, relationTypes, onSuccess, onFailure);
  169 + enqueueForTellNext(tpi, tbMsg, relationTypes, null, onSuccess, onFailure);
164 170 }
165 171
166 172 @Override
167 173 public void enqueueForTellNext(TbMsg tbMsg, String queueName, String relationType, Runnable onSuccess, Consumer<Throwable> onFailure) {
168   - TopicPartitionInfo tpi = mainCtx.resolve(ServiceType.TB_RULE_ENGINE, getTenantId(), tbMsg.getOriginator());
169   - enqueueForTellNext(tpi, tbMsg, Collections.singleton(relationType), onSuccess, onFailure);
  174 + TopicPartitionInfo tpi = mainCtx.resolve(ServiceType.TB_RULE_ENGINE, queueName, getTenantId(), tbMsg.getOriginator());
  175 + enqueueForTellNext(tpi, tbMsg, Collections.singleton(relationType), null, onSuccess, onFailure);
170 176 }
171 177
172 178 @Override
173 179 public void enqueueForTellNext(TbMsg tbMsg, String queueName, Set<String> relationTypes, Runnable onSuccess, Consumer<Throwable> onFailure) {
174 180 TopicPartitionInfo tpi = mainCtx.resolve(ServiceType.TB_RULE_ENGINE, queueName, getTenantId(), tbMsg.getOriginator());
175   - enqueueForTellNext(tpi, tbMsg, relationTypes, onSuccess, onFailure);
  181 + enqueueForTellNext(tpi, tbMsg, relationTypes, null, onSuccess, onFailure);
176 182 }
177 183
178   - private void enqueueForTellNext(TopicPartitionInfo tpi, TbMsg tbMsg, Set<String> relationTypes, Runnable onSuccess, Consumer<Throwable> onFailure) {
  184 + private void enqueueForTellNext(TopicPartitionInfo tpi, TbMsg tbMsg, Set<String> relationTypes, String failureMessage, Runnable onSuccess, Consumer<Throwable> onFailure) {
179 185 RuleChainId ruleChainId = nodeCtx.getSelf().getRuleChainId();
180 186 RuleNodeId ruleNodeId = nodeCtx.getSelf().getId();
181 187 tbMsg = TbMsg.newMsg(tbMsg, ruleChainId, ruleNodeId);
182   - TransportProtos.ToRuleEngineMsg msg = TransportProtos.ToRuleEngineMsg.newBuilder()
  188 + TransportProtos.ToRuleEngineMsg.Builder msg = TransportProtos.ToRuleEngineMsg.newBuilder()
183 189 .setTenantIdMSB(getTenantId().getId().getMostSignificantBits())
184 190 .setTenantIdLSB(getTenantId().getId().getLeastSignificantBits())
185 191 .setTbMsg(TbMsg.toByteString(tbMsg))
186   - .addAllRelationTypes(relationTypes)
187   - .build();
188   - mainCtx.getProducerProvider().getRuleEngineMsgProducer().send(tpi, new TbProtoQueueMsg<>(tbMsg.getId(), msg), new SimpleTbQueueCallback(onSuccess, onFailure));
  192 + .addAllRelationTypes(relationTypes);
  193 + if (failureMessage != null) {
  194 + msg.setFailureMessage(failureMessage);
  195 + }
  196 + mainCtx.getProducerProvider().getRuleEngineMsgProducer().send(tpi, new TbProtoQueueMsg<>(tbMsg.getId(), msg.build()), new SimpleTbQueueCallback(onSuccess, onFailure));
189 197 }
190 198
191 199 @Override
... ... @@ -207,7 +215,8 @@ class DefaultTbContext implements TbContext {
207 215 if (nodeCtx.getSelf().isDebugMode()) {
208 216 mainCtx.persistDebugOutput(nodeCtx.getTenantId(), nodeCtx.getSelf().getId(), msg, TbRelationTypes.FAILURE, th);
209 217 }
210   - nodeCtx.getChainActor().tell(new RuleNodeToRuleChainTellNextMsg(nodeCtx.getSelf().getId(), Collections.singleton(TbRelationTypes.FAILURE), msg), nodeCtx.getSelfActor());
  218 + nodeCtx.getChainActor().tell(new RuleNodeToRuleChainTellNextMsg(nodeCtx.getSelf().getId(), Collections.singleton(TbRelationTypes.FAILURE),
  219 + msg, th != null ? th.getMessage() : null), nodeCtx.getSelfActor());
211 220 }
212 221
213 222 public void updateSelf(RuleNode self) {
... ...
1   -/**
2   - * Copyright © 2016-2020 The Thingsboard Authors
3   - *
4   - * Licensed under the Apache License, Version 2.0 (the "License");
5   - * you may not use this file except in compliance with the License.
6   - * You may obtain a copy of the License at
7   - *
8   - * http://www.apache.org/licenses/LICENSE-2.0
9   - *
10   - * Unless required by applicable law or agreed to in writing, software
11   - * distributed under the License is distributed on an "AS IS" BASIS,
12   - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   - * See the License for the specific language governing permissions and
14   - * limitations under the License.
15   - */
16   -package org.thingsboard.server.actors.ruleChain;
17   -
18   -import lombok.Data;
19   -import org.thingsboard.server.common.data.id.RuleChainId;
20   -import org.thingsboard.server.common.data.id.TenantId;
21   -import org.thingsboard.server.common.msg.MsgType;
22   -import org.thingsboard.server.common.msg.aware.RuleChainAwareMsg;
23   -import org.thingsboard.server.common.msg.aware.TenantAwareMsg;
24   -
25   -import java.io.Serializable;
26   -
27   -/**
28   - * Created by ashvayka on 19.03.18.
29   - */
30   -@Data
31   -final class RemoteToRuleChainTellNextMsg extends RuleNodeToRuleChainTellNextMsg implements TenantAwareMsg, RuleChainAwareMsg {
32   -
33   - private static final long serialVersionUID = 2459605482321657447L;
34   - private final TenantId tenantId;
35   - private final RuleChainId ruleChainId;
36   -
37   - public RemoteToRuleChainTellNextMsg(RuleNodeToRuleChainTellNextMsg original, TenantId tenantId, RuleChainId ruleChainId) {
38   - super(original.getOriginator(), original.getRelationTypes(), original.getMsg());
39   - this.tenantId = tenantId;
40   - this.ruleChainId = ruleChainId;
41   - }
42   -
43   - @Override
44   - public MsgType getMsgType() {
45   - return MsgType.REMOTE_TO_RULE_CHAIN_TELL_NEXT_MSG;
46   - }
47   -
48   -}
... ... @@ -22,6 +22,7 @@ import org.thingsboard.server.actors.service.ComponentActor;
22 22 import org.thingsboard.server.actors.service.ContextBasedCreator;
23 23 import org.thingsboard.server.common.data.id.RuleChainId;
24 24 import org.thingsboard.server.common.data.id.TenantId;
  25 +import org.thingsboard.server.common.data.rule.RuleChain;
25 26 import org.thingsboard.server.common.msg.TbActorMsg;
26 27 import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg;
27 28 import org.thingsboard.server.common.msg.queue.PartitionChangeMsg;
... ... @@ -30,9 +31,9 @@ import scala.concurrent.duration.Duration;
30 31
31 32 public class RuleChainActor extends ComponentActor<RuleChainId, RuleChainActorMessageProcessor> {
32 33
33   - private RuleChainActor(ActorSystemContext systemContext, TenantId tenantId, RuleChainId ruleChainId) {
34   - super(systemContext, tenantId, ruleChainId);
35   - setProcessor(new RuleChainActorMessageProcessor(tenantId, ruleChainId, systemContext,
  34 + private RuleChainActor(ActorSystemContext systemContext, TenantId tenantId, RuleChain ruleChain) {
  35 + super(systemContext, tenantId, ruleChain.getId());
  36 + setProcessor(new RuleChainActorMessageProcessor(tenantId, ruleChain, systemContext,
36 37 context().parent(), context().self()));
37 38 }
38 39
... ... @@ -46,7 +47,6 @@ public class RuleChainActor extends ComponentActor<RuleChainId, RuleChainActorMe
46 47 processor.onQueueToRuleEngineMsg((QueueToRuleEngineMsg) msg);
47 48 break;
48 49 case RULE_TO_RULE_CHAIN_TELL_NEXT_MSG:
49   - case REMOTE_TO_RULE_CHAIN_TELL_NEXT_MSG:
50 50 processor.onTellNext((RuleNodeToRuleChainTellNextMsg) msg);
51 51 break;
52 52 case RULE_CHAIN_TO_RULE_CHAIN_MSG:
... ... @@ -68,17 +68,17 @@ public class RuleChainActor extends ComponentActor<RuleChainId, RuleChainActorMe
68 68 private static final long serialVersionUID = 1L;
69 69
70 70 private final TenantId tenantId;
71   - private final RuleChainId ruleChainId;
  71 + private final RuleChain ruleChain;
72 72
73   - public ActorCreator(ActorSystemContext context, TenantId tenantId, RuleChainId pluginId) {
  73 + public ActorCreator(ActorSystemContext context, TenantId tenantId, RuleChain ruleChain) {
74 74 super(context);
75 75 this.tenantId = tenantId;
76   - this.ruleChainId = pluginId;
  76 + this.ruleChain = ruleChain;
77 77 }
78 78
79 79 @Override
80 80 public RuleChainActor create() {
81   - return new RuleChainActor(context, tenantId, ruleChainId);
  81 + return new RuleChainActor(context, tenantId, ruleChain);
82 82 }
83 83 }
84 84
... ...
... ... @@ -5,7 +5,7 @@
5 5 * you may not use this file except in compliance with the License.
6 6 * You may obtain a copy of the License at
7 7 *
8   - * http://www.apache.org/licenses/LICENSE-2.0
  8 + * http://www.apache.org/licenses/LICENSE-2.0
9 9 *
10 10 * Unless required by applicable law or agreed to in writing, software
11 11 * distributed under the License is distributed on an "AS IS" BASIS,
... ... @@ -37,6 +37,8 @@ import org.thingsboard.server.common.msg.TbMsg;
37 37 import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg;
38 38 import org.thingsboard.server.common.msg.queue.PartitionChangeMsg;
39 39 import org.thingsboard.server.common.msg.queue.QueueToRuleEngineMsg;
  40 +import org.thingsboard.server.common.msg.queue.RuleEngineException;
  41 +import org.thingsboard.server.common.msg.queue.RuleNodeException;
40 42 import org.thingsboard.server.common.msg.queue.ServiceType;
41 43 import org.thingsboard.server.common.msg.queue.TopicPartitionInfo;
42 44 import org.thingsboard.server.dao.rule.RuleChainService;
... ... @@ -67,14 +69,16 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh
67 69 private final Map<RuleNodeId, List<RuleNodeRelation>> nodeRoutes;
68 70 private final RuleChainService service;
69 71 private final TbQueueProducer<TbProtoQueueMsg<ToRuleEngineMsg>> producer;
  72 + private String ruleChainName;
70 73
71 74 private RuleNodeId firstId;
72 75 private RuleNodeCtx firstNode;
73 76 private boolean started;
74 77
75   - RuleChainActorMessageProcessor(TenantId tenantId, RuleChainId ruleChainId, ActorSystemContext systemContext
  78 + RuleChainActorMessageProcessor(TenantId tenantId, RuleChain ruleChain, ActorSystemContext systemContext
76 79 , ActorRef parent, ActorRef self) {
77   - super(systemContext, tenantId, ruleChainId);
  80 + super(systemContext, tenantId, ruleChain.getId());
  81 + this.ruleChainName = ruleChain.getName();
78 82 this.parent = parent;
79 83 this.self = self;
80 84 this.nodeActors = new HashMap<>();
... ... @@ -113,6 +117,7 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh
113 117 public void onUpdate(ActorContext context) {
114 118 RuleChain ruleChain = service.findRuleChainById(tenantId, entityId);
115 119 if (ruleChain != null) {
  120 + ruleChainName = ruleChain.getName();
116 121 List<RuleNode> ruleNodeList = service.getRuleChainNodes(tenantId, entityId);
117 122 log.trace("[{}][{}] Updating rule chain with {} nodes", tenantId, entityId, ruleNodeList.size());
118 123 for (RuleNode ruleNode : ruleNodeList) {
... ... @@ -194,7 +199,7 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh
194 199 void onQueueToRuleEngineMsg(QueueToRuleEngineMsg envelope) {
195 200 TbMsg msg = envelope.getTbMsg();
196 201 log.trace("[{}][{}] Processing message [{}]: {}", entityId, firstId, msg.getId(), msg);
197   - if (envelope.getRelationTypes() == null) {
  202 + if (envelope.getRelationTypes() == null || envelope.getRelationTypes().isEmpty()) {
198 203 try {
199 204 checkActive();
200 205 RuleNodeId targetId = msg.getRuleNodeId();
... ... @@ -213,10 +218,10 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh
213 218 msg.getCallback().onSuccess();
214 219 }
215 220 } catch (Exception e) {
216   - envelope.getTbMsg().getCallback().onFailure(e);
  221 + envelope.getTbMsg().getCallback().onFailure(new RuleEngineException(e.getMessage()));
217 222 }
218 223 } else {
219   - onTellNext(envelope.getTbMsg(), envelope.getTbMsg().getRuleNodeId(), envelope.getRelationTypes());
  224 + onTellNext(envelope.getTbMsg(), envelope.getTbMsg().getRuleNodeId(), envelope.getRelationTypes(), envelope.getFailureMessage());
220 225 }
221 226 }
222 227
... ... @@ -230,10 +235,10 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh
230 235 }
231 236
232 237 void onTellNext(RuleNodeToRuleChainTellNextMsg envelope) {
233   - onTellNext(envelope.getMsg(), envelope.getOriginator(), envelope.getRelationTypes());
  238 + onTellNext(envelope.getMsg(), envelope.getOriginator(), envelope.getRelationTypes(), envelope.getFailureMessage());
234 239 }
235 240
236   - private void onTellNext(TbMsg msg, RuleNodeId originatorNodeId, Set<String> relationTypes) {
  241 + private void onTellNext(TbMsg msg, RuleNodeId originatorNodeId, Set<String> relationTypes, String failureMessage) {
237 242 try {
238 243 checkActive();
239 244 EntityId entityId = msg.getOriginator();
... ... @@ -245,9 +250,14 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh
245 250 if (relationsCount == 0) {
246 251 log.trace("[{}][{}][{}] No outbound relations to process", tenantId, entityId, msg.getId());
247 252 if (relationTypes.contains(TbRelationTypes.FAILURE)) {
248   - log.debug("[{}] Failure during message processing by Rule Node [{}]. Enable and see debug events for more info", entityId, originatorNodeId.getId());
249   - //TODO 2.5: Introduce our own RuleEngineFailureException to track what is wrong
250   - msg.getCallback().onFailure(new RuntimeException("Failure during message processing by Rule Node [" + originatorNodeId.getId().toString() + "]"));
  253 + RuleNodeCtx ruleNodeCtx = nodeActors.get(originatorNodeId);
  254 + if (ruleNodeCtx != null) {
  255 + msg.getCallback().onFailure(new RuleNodeException(failureMessage, ruleChainName, ruleNodeCtx.getSelf()));
  256 + } else {
  257 + log.debug("[{}] Failure during message processing by Rule Node [{}]. Enable and see debug events for more info", entityId, originatorNodeId.getId());
  258 + //TODO 2.5: Introduce our own RuleEngineFailureException to track what is wrong
  259 + msg.getCallback().onFailure(new RuleEngineException("Failure during message processing by Rule Node [" + originatorNodeId.getId().toString() + "]"));
  260 + }
251 261 } else {
252 262 msg.getCallback().onSuccess();
253 263 }
... ... @@ -265,7 +275,7 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh
265 275 }
266 276 }
267 277 } catch (Exception e) {
268   - msg.getCallback().onFailure(e);
  278 + msg.getCallback().onFailure(new RuleEngineException("onTellNext - " + e.getMessage()));
269 279 }
270 280 }
271 281
... ...
... ... @@ -15,43 +15,89 @@
15 15 */
16 16 package org.thingsboard.server.actors.ruleChain;
17 17
  18 +import akka.actor.ActorContext;
18 19 import akka.actor.ActorRef;
  20 +import akka.actor.Props;
  21 +import com.google.common.collect.BiMap;
  22 +import com.google.common.collect.HashBiMap;
  23 +import lombok.Getter;
19 24 import org.thingsboard.server.actors.ActorSystemContext;
20 25 import org.thingsboard.server.actors.service.ContextAwareActor;
21   -import org.thingsboard.server.actors.shared.rulechain.RuleChainManager;
  26 +import org.thingsboard.server.actors.service.DefaultActorService;
  27 +import org.thingsboard.server.common.data.EntityType;
22 28 import org.thingsboard.server.common.data.id.EntityId;
23 29 import org.thingsboard.server.common.data.id.RuleChainId;
  30 +import org.thingsboard.server.common.data.id.TenantId;
  31 +import org.thingsboard.server.common.data.page.PageDataIterable;
  32 +import org.thingsboard.server.common.data.rule.RuleChain;
24 33 import org.thingsboard.server.dao.rule.RuleChainService;
25 34
  35 +import java.util.function.Function;
  36 +
26 37 /**
27 38 * Created by ashvayka on 15.03.18.
28 39 */
29 40 public abstract class RuleChainManagerActor extends ContextAwareActor {
30 41
31   - protected final RuleChainManager ruleChainManager;
32   - protected final RuleChainService ruleChainService;
  42 + protected final TenantId tenantId;
  43 + private final RuleChainService ruleChainService;
  44 + private final BiMap<RuleChainId, ActorRef> actors;
  45 + @Getter
  46 + protected RuleChain rootChain;
  47 + @Getter
  48 + protected ActorRef rootChainActor;
33 49
34   - public RuleChainManagerActor(ActorSystemContext systemContext, RuleChainManager ruleChainManager) {
  50 + public RuleChainManagerActor(ActorSystemContext systemContext, TenantId tenantId) {
35 51 super(systemContext);
36   - this.ruleChainManager = ruleChainManager;
  52 + this.tenantId = tenantId;
  53 + this.actors = HashBiMap.create();
37 54 this.ruleChainService = systemContext.getRuleChainService();
38 55 }
39 56
40 57 protected void initRuleChains() {
41   - ruleChainManager.init(this.context());
  58 + for (RuleChain ruleChain : new PageDataIterable<>(link -> ruleChainService.findTenantRuleChains(tenantId, link), ContextAwareActor.ENTITY_PACK_LIMIT)) {
  59 + RuleChainId ruleChainId = ruleChain.getId();
  60 + log.debug("[{}|{}] Creating rule chain actor", ruleChainId.getEntityType(), ruleChain.getId());
  61 + //TODO: remove this cast making UUIDBased subclass of EntityId an interface and vice versa.
  62 + ActorRef actorRef = getOrCreateActor(this.context(), ruleChainId, id -> ruleChain);
  63 + visit(ruleChain, actorRef);
  64 + log.debug("[{}|{}] Rule Chain actor created.", ruleChainId.getEntityType(), ruleChainId.getId());
  65 + }
  66 + }
  67 +
  68 + protected void visit(RuleChain entity, ActorRef actorRef) {
  69 + if (entity != null && entity.isRoot()) {
  70 + rootChain = entity;
  71 + rootChainActor = actorRef;
  72 + }
  73 + }
  74 +
  75 + public ActorRef getOrCreateActor(ActorContext context, RuleChainId ruleChainId) {
  76 + return getOrCreateActor(context, ruleChainId, eId -> ruleChainService.findRuleChainById(TenantId.SYS_TENANT_ID, eId));
  77 + }
  78 +
  79 + public ActorRef getOrCreateActor(ActorContext context, RuleChainId ruleChainId, Function<RuleChainId, RuleChain> provider) {
  80 + return actors.computeIfAbsent(ruleChainId, eId -> {
  81 + RuleChain ruleChain = provider.apply(eId);
  82 + return context.actorOf(Props.create(new RuleChainActor.ActorCreator(systemContext, tenantId, ruleChain))
  83 + .withDispatcher(DefaultActorService.TENANT_RULE_DISPATCHER_NAME), eId.toString());
  84 + });
42 85 }
43 86
44 87 protected ActorRef getEntityActorRef(EntityId entityId) {
45 88 ActorRef target = null;
46   - switch (entityId.getEntityType()) {
47   - case RULE_CHAIN:
48   - target = ruleChainManager.getOrCreateActor(this.context(), (RuleChainId) entityId);
49   - break;
  89 + if (entityId.getEntityType() == EntityType.RULE_CHAIN) {
  90 + target = getOrCreateActor(this.context(), (RuleChainId) entityId);
50 91 }
51 92 return target;
52 93 }
53 94
54 95 protected void broadcast(Object msg) {
55   - ruleChainManager.broadcast(msg);
  96 + actors.values().forEach(actorRef -> actorRef.tell(msg, ActorRef.noSender()));
56 97 }
  98 +
  99 + public ActorRef get(RuleChainId id) {
  100 + return actors.get(id);
  101 + }
  102 +
57 103 }
... ...
... ... @@ -34,6 +34,7 @@ class RuleNodeToRuleChainTellNextMsg implements TbActorMsg, Serializable {
34 34 private final RuleNodeId originator;
35 35 private final Set<String> relationTypes;
36 36 private final TbMsg msg;
  37 + private final String failureMessage;
37 38
38 39 @Override
39 40 public MsgType getMsgType() {
... ...
1   -/**
2   - * Copyright © 2016-2020 The Thingsboard Authors
3   - *
4   - * Licensed under the Apache License, Version 2.0 (the "License");
5   - * you may not use this file except in compliance with the License.
6   - * You may obtain a copy of the License at
7   - *
8   - * http://www.apache.org/licenses/LICENSE-2.0
9   - *
10   - * Unless required by applicable law or agreed to in writing, software
11   - * distributed under the License is distributed on an "AS IS" BASIS,
12   - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   - * See the License for the specific language governing permissions and
14   - * limitations under the License.
15   - */
16   -package org.thingsboard.server.actors.shared;
17   -
18   -import akka.actor.ActorContext;
19   -import akka.actor.ActorRef;
20   -import akka.actor.Props;
21   -import akka.actor.UntypedActor;
22   -import akka.japi.Creator;
23   -import com.google.common.collect.BiMap;
24   -import com.google.common.collect.HashBiMap;
25   -import lombok.extern.slf4j.Slf4j;
26   -import org.thingsboard.server.actors.ActorSystemContext;
27   -import org.thingsboard.server.actors.ruleChain.RuleChainActor;
28   -import org.thingsboard.server.actors.service.ContextAwareActor;
29   -import org.thingsboard.server.common.data.SearchTextBased;
30   -import org.thingsboard.server.common.data.id.EntityId;
31   -import org.thingsboard.server.common.data.id.RuleChainId;
32   -import org.thingsboard.server.common.data.id.TenantId;
33   -import org.thingsboard.server.common.data.id.UUIDBased;
34   -import org.thingsboard.server.common.data.page.PageDataIterable;
35   -
36   -import java.util.HashMap;
37   -import java.util.Map;
38   -
39   -/**
40   - * Created by ashvayka on 15.03.18.
41   - */
42   -@Slf4j
43   -public abstract class EntityActorsManager<T extends EntityId, A extends UntypedActor, M extends SearchTextBased<? extends UUIDBased>> {
44   -
45   - protected final ActorSystemContext systemContext;
46   - protected final BiMap<T, ActorRef> actors;
47   -
48   - public EntityActorsManager(ActorSystemContext systemContext) {
49   - this.systemContext = systemContext;
50   - this.actors = HashBiMap.create();
51   - }
52   -
53   - protected abstract TenantId getTenantId();
54   -
55   - protected abstract String getDispatcherName();
56   -
57   - protected abstract Creator<A> creator(T entityId);
58   -
59   - protected abstract PageDataIterable.FetchFunction<M> getFetchEntitiesFunction();
60   -
61   - public void init(ActorContext context) {
62   - for (M entity : new PageDataIterable<>(getFetchEntitiesFunction(), ContextAwareActor.ENTITY_PACK_LIMIT)) {
63   - T entityId = (T) entity.getId();
64   - log.debug("[{}|{}] Creating entity actor", entityId.getEntityType(), entityId.getId());
65   - //TODO: remove this cast making UUIDBased subclass of EntityId an interface and vice versa.
66   - ActorRef actorRef = getOrCreateActor(context, entityId);
67   - visit(entity, actorRef);
68   - log.debug("[{}|{}] Entity actor created.", entityId.getEntityType(), entityId.getId());
69   - }
70   - }
71   -
72   - public void visit(M entity, ActorRef actorRef) {
73   - }
74   -
75   - public ActorRef getOrCreateActor(ActorContext context, T entityId) {
76   - return actors.computeIfAbsent(entityId, eId ->
77   - context.actorOf(Props.create(creator(eId))
78   - .withDispatcher(getDispatcherName()), eId.toString()));
79   - }
80   -
81   - public void broadcast(Object msg) {
82   - actors.values().forEach(actorRef -> actorRef.tell(msg, ActorRef.noSender()));
83   - }
84   -
85   - public void remove(T id) {
86   - actors.remove(id);
87   - }
88   -
89   - public ActorRef get(T id) {
90   - return actors.get(id);
91   - }
92   -
93   -}
1   -/**
2   - * Copyright © 2016-2020 The Thingsboard Authors
3   - *
4   - * Licensed under the Apache License, Version 2.0 (the "License");
5   - * you may not use this file except in compliance with the License.
6   - * You may obtain a copy of the License at
7   - *
8   - * http://www.apache.org/licenses/LICENSE-2.0
9   - *
10   - * Unless required by applicable law or agreed to in writing, software
11   - * distributed under the License is distributed on an "AS IS" BASIS,
12   - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   - * See the License for the specific language governing permissions and
14   - * limitations under the License.
15   - */
16   -package org.thingsboard.server.actors.shared.rulechain;
17   -
18   -import akka.actor.ActorRef;
19   -import akka.japi.Creator;
20   -import lombok.Getter;
21   -import lombok.extern.slf4j.Slf4j;
22   -import org.thingsboard.server.actors.ActorSystemContext;
23   -import org.thingsboard.server.actors.ruleChain.RuleChainActor;
24   -import org.thingsboard.server.actors.shared.EntityActorsManager;
25   -import org.thingsboard.server.common.data.id.RuleChainId;
26   -import org.thingsboard.server.common.data.rule.RuleChain;
27   -import org.thingsboard.server.dao.rule.RuleChainService;
28   -
29   -/**
30   - * Created by ashvayka on 15.03.18.
31   - */
32   -@Slf4j
33   -public abstract class RuleChainManager extends EntityActorsManager<RuleChainId, RuleChainActor, RuleChain> {
34   -
35   - protected final RuleChainService service;
36   - @Getter
37   - protected RuleChain rootChain;
38   - @Getter
39   - protected ActorRef rootChainActor;
40   -
41   - public RuleChainManager(ActorSystemContext systemContext) {
42   - super(systemContext);
43   - this.service = systemContext.getRuleChainService();
44   - }
45   -
46   - @Override
47   - public Creator<RuleChainActor> creator(RuleChainId entityId) {
48   - return new RuleChainActor.ActorCreator(systemContext, getTenantId(), entityId);
49   - }
50   -
51   - @Override
52   - public void visit(RuleChain entity, ActorRef actorRef) {
53   - if (entity != null && entity.isRoot()) {
54   - rootChain = entity;
55   - rootChainActor = actorRef;
56   - }
57   - }
58   -
59   -}
1   -/**
2   - * Copyright © 2016-2020 The Thingsboard Authors
3   - *
4   - * Licensed under the Apache License, Version 2.0 (the "License");
5   - * you may not use this file except in compliance with the License.
6   - * You may obtain a copy of the License at
7   - *
8   - * http://www.apache.org/licenses/LICENSE-2.0
9   - *
10   - * Unless required by applicable law or agreed to in writing, software
11   - * distributed under the License is distributed on an "AS IS" BASIS,
12   - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   - * See the License for the specific language governing permissions and
14   - * limitations under the License.
15   - */
16   -package org.thingsboard.server.actors.shared.rulechain;
17   -
18   -import akka.actor.ActorContext;
19   -import org.thingsboard.server.actors.ActorSystemContext;
20   -import org.thingsboard.server.actors.service.DefaultActorService;
21   -import org.thingsboard.server.common.data.id.TenantId;
22   -import org.thingsboard.server.common.data.page.PageDataIterable.FetchFunction;
23   -import org.thingsboard.server.common.data.rule.RuleChain;
24   -
25   -public class TenantRuleChainManager extends RuleChainManager {
26   -
27   - private final TenantId tenantId;
28   -
29   - public TenantRuleChainManager(ActorSystemContext systemContext, TenantId tenantId) {
30   - super(systemContext);
31   - this.tenantId = tenantId;
32   - }
33   -
34   - @Override
35   - public void init(ActorContext context) {
36   - super.init(context);
37   - }
38   -
39   - @Override
40   - protected TenantId getTenantId() {
41   - return tenantId;
42   - }
43   -
44   - @Override
45   - protected String getDispatcherName() {
46   - return DefaultActorService.TENANT_RULE_DISPATCHER_NAME;
47   - }
48   -
49   - @Override
50   - protected FetchFunction<RuleChain> getFetchEntitiesFunction() {
51   - return link -> service.findTenantRuleChains(tenantId, link);
52   - }
53   -}
... ... @@ -24,7 +24,6 @@ import org.thingsboard.server.actors.service.ContextBasedCreator;
24 24 import org.thingsboard.server.common.data.DataConstants;
25 25 import org.thingsboard.server.common.data.Event;
26 26 import org.thingsboard.server.common.msg.TbActorMsg;
27   -import org.thingsboard.server.common.msg.cluster.ServerAddress;
28 27
29 28 @Slf4j
30 29 public class StatsActor extends ContextAwareActor {
... ...
... ... @@ -30,7 +30,6 @@ import org.thingsboard.server.actors.device.DeviceActorCreator;
30 30 import org.thingsboard.server.actors.ruleChain.RuleChainManagerActor;
31 31 import org.thingsboard.server.actors.service.ContextBasedCreator;
32 32 import org.thingsboard.server.actors.service.DefaultActorService;
33   -import org.thingsboard.server.actors.shared.rulechain.TenantRuleChainManager;
34 33 import org.thingsboard.server.common.data.EntityType;
35 34 import org.thingsboard.server.common.data.id.DeviceId;
36 35 import org.thingsboard.server.common.data.id.RuleChainId;
... ... @@ -43,6 +42,7 @@ import org.thingsboard.server.common.msg.aware.RuleChainAwareMsg;
43 42 import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg;
44 43 import org.thingsboard.server.common.msg.queue.PartitionChangeMsg;
45 44 import org.thingsboard.server.common.msg.queue.QueueToRuleEngineMsg;
  45 +import org.thingsboard.server.common.msg.queue.RuleEngineException;
46 46 import org.thingsboard.server.common.msg.queue.ServiceType;
47 47 import scala.concurrent.duration.Duration;
48 48
... ... @@ -51,12 +51,12 @@ import java.util.stream.Collectors;
51 51
52 52 public class TenantActor extends RuleChainManagerActor {
53 53
54   - private final TenantId tenantId;
55 54 private final BiMap<DeviceId, ActorRef> deviceActors;
  55 + private boolean isRuleEngine;
  56 + private boolean isCore;
56 57
57 58 private TenantActor(ActorSystemContext systemContext, TenantId tenantId) {
58   - super(systemContext, new TenantRuleChainManager(systemContext, tenantId));
59   - this.tenantId = tenantId;
  59 + super(systemContext, tenantId);
60 60 this.deviceActors = HashBiMap.create();
61 61 }
62 62
... ... @@ -69,7 +69,11 @@ public class TenantActor extends RuleChainManagerActor {
69 69 public void preStart() {
70 70 log.info("[{}] Starting tenant actor.", tenantId);
71 71 try {
72   - initRuleChains();
  72 + isRuleEngine = systemContext.getServiceInfoProvider().isService(ServiceType.TB_RULE_ENGINE);
  73 + isCore = systemContext.getServiceInfoProvider().isService(ServiceType.TB_CORE);
  74 + if (isRuleEngine) {
  75 + initRuleChains();
  76 + }
73 77 log.info("[{}] Tenant actor started.", tenantId);
74 78 } catch (Exception e) {
75 79 log.warn("[{}] Unknown failure", tenantId, e);
... ... @@ -115,7 +119,6 @@ public class TenantActor extends RuleChainManagerActor {
115 119 onToDeviceActorMsg((DeviceAwareMsg) msg);
116 120 break;
117 121 case RULE_CHAIN_TO_RULE_CHAIN_MSG:
118   - case REMOTE_TO_RULE_CHAIN_TELL_NEXT_MSG:
119 122 onRuleChainMsg((RuleChainAwareMsg) msg);
120 123 break;
121 124 default:
... ... @@ -129,16 +132,19 @@ public class TenantActor extends RuleChainManagerActor {
129 132 }
130 133
131 134 private void onQueueToRuleEngineMsg(QueueToRuleEngineMsg msg) {
  135 + if (!isRuleEngine) {
  136 + log.warn("RECEIVED INVALID MESSAGE: {}", msg);
  137 + }
132 138 TbMsg tbMsg = msg.getTbMsg();
133 139 if (tbMsg.getRuleChainId() == null) {
134   - if (ruleChainManager.getRootChainActor() != null) {
135   - ruleChainManager.getRootChainActor().tell(msg, self());
  140 + if (getRootChainActor() != null) {
  141 + getRootChainActor().tell(msg, self());
136 142 } else {
137   - tbMsg.getCallback().onFailure(new RuntimeException("No Root Rule Chain available!"));
  143 + tbMsg.getCallback().onFailure(new RuleEngineException("No Root Rule Chain available!"));
138 144 log.info("[{}] No Root Chain: {}", tenantId, msg);
139 145 }
140 146 } else {
141   - ActorRef ruleChainActor = ruleChainManager.get(tbMsg.getRuleChainId());
  147 + ActorRef ruleChainActor = get(tbMsg.getRuleChainId());
142 148 if (ruleChainActor != null) {
143 149 ruleChainActor.tell(msg, self());
144 150 } else {
... ... @@ -150,24 +156,29 @@ public class TenantActor extends RuleChainManagerActor {
150 156 }
151 157
152 158 private void onRuleChainMsg(RuleChainAwareMsg msg) {
153   - ruleChainManager.getOrCreateActor(context(), msg.getRuleChainId()).tell(msg, self());
  159 + getOrCreateActor(context(), msg.getRuleChainId()).tell(msg, self());
154 160 }
155 161
156 162 private void onToDeviceActorMsg(DeviceAwareMsg msg) {
  163 + if (!isCore) {
  164 + log.warn("RECEIVED INVALID MESSAGE: {}", msg);
  165 + }
157 166 getOrCreateDeviceActor(msg.getDeviceId()).tell(msg, ActorRef.noSender());
158 167 }
159 168
160 169 private void onComponentLifecycleMsg(ComponentLifecycleMsg msg) {
161   - ActorRef target = getEntityActorRef(msg.getEntityId());
162   - if (target != null) {
163   - if (msg.getEntityId().getEntityType() == EntityType.RULE_CHAIN) {
164   - RuleChain ruleChain = systemContext.getRuleChainService().
165   - findRuleChainById(tenantId, new RuleChainId(msg.getEntityId().getId()));
166   - ruleChainManager.visit(ruleChain, target);
  170 + if (isRuleEngine) {
  171 + ActorRef target = getEntityActorRef(msg.getEntityId());
  172 + if (target != null) {
  173 + if (msg.getEntityId().getEntityType() == EntityType.RULE_CHAIN) {
  174 + RuleChain ruleChain = systemContext.getRuleChainService().
  175 + findRuleChainById(tenantId, new RuleChainId(msg.getEntityId().getId()));
  176 + visit(ruleChain, target);
  177 + }
  178 + target.tell(msg, ActorRef.noSender());
  179 + } else {
  180 + log.debug("[{}] Invalid component lifecycle msg: {}", tenantId, msg);
167 181 }
168   - target.tell(msg, ActorRef.noSender());
169   - } else {
170   - log.debug("[{}] Invalid component lifecycle msg: {}", tenantId, msg);
171 182 }
172 183 }
173 184
... ... @@ -214,15 +225,12 @@ public class TenantActor extends RuleChainManagerActor {
214 225 }
215 226 }
216 227
217   - private final SupervisorStrategy strategy = new OneForOneStrategy(3, Duration.create("1 minute"), new Function<Throwable, SupervisorStrategy.Directive>() {
218   - @Override
219   - public SupervisorStrategy.Directive apply(Throwable t) {
220   - log.warn("[{}] Unknown failure", tenantId, t);
221   - if (t instanceof ActorInitializationException) {
222   - return SupervisorStrategy.stop();
223   - } else {
224   - return SupervisorStrategy.resume();
225   - }
  228 + private final SupervisorStrategy strategy = new OneForOneStrategy(3, Duration.create("1 minute"), t -> {
  229 + log.warn("[{}] Unknown failure", tenantId, t);
  230 + if (t instanceof ActorInitializationException) {
  231 + return SupervisorStrategy.stop();
  232 + } else {
  233 + return SupervisorStrategy.resume();
226 234 }
227 235 });
228 236
... ...
... ... @@ -92,10 +92,10 @@ public class TbWebSocketHandler extends TextWebSocketHandler implements Telemetr
92 92 try {
93 93 SessionMetaData sessionMd = internalSessionMap.get(session.getId());
94 94 if (sessionMd != null) {
95   - log.info("[{}][{}] Processing {}", sessionMd.sessionRef.getSecurityCtx().getTenantId(), session.getId(), message.getPayload());
  95 + log.trace("[{}][{}] Processing {}", sessionMd.sessionRef.getSecurityCtx().getTenantId(), session.getId(), message.getPayload());
96 96 webSocketService.handleWebSocketMsg(sessionMd.sessionRef, message.getPayload());
97 97 } else {
98   - log.warn("[{}] Failed to find session", session.getId());
  98 + log.trace("[{}] Failed to find session", session.getId());
99 99 session.close(CloseStatus.SERVER_ERROR.withReason("Session not found!"));
100 100 }
101 101 } catch (IOException e) {
... ... @@ -139,7 +139,7 @@ public class TbWebSocketHandler extends TextWebSocketHandler implements Telemetr
139 139 if (sessionMd != null) {
140 140 processInWebSocketService(sessionMd.sessionRef, SessionEvent.onError(tError));
141 141 } else {
142   - log.warn("[{}] Failed to find session", session.getId());
  142 + log.trace("[{}] Failed to find session", session.getId());
143 143 }
144 144 log.trace("[{}] Session transport error", session.getId(), tError);
145 145 }
... ...
... ... @@ -25,7 +25,7 @@ import org.thingsboard.server.actors.ActorSystemContext;
25 25 import org.thingsboard.server.common.data.id.TenantId;
26 26 import org.thingsboard.server.common.msg.TbActorMsg;
27 27 import org.thingsboard.server.common.msg.queue.ServiceType;
28   -import org.thingsboard.server.common.msg.queue.TbMsgCallback;
  28 +import org.thingsboard.server.common.msg.queue.TbCallback;
29 29 import org.thingsboard.server.gen.transport.TransportProtos.DeviceStateServiceMsgProto;
30 30 import org.thingsboard.server.gen.transport.TransportProtos.FromDeviceRPCResponseProto;
31 31 import org.thingsboard.server.gen.transport.TransportProtos.LocalSubscriptionServiceMsgProto;
... ... @@ -120,8 +120,8 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService<ToCore
120 120 ConcurrentMap<UUID, TbProtoQueueMsg<ToCoreMsg>> failedMap = new ConcurrentHashMap<>();
121 121 CountDownLatch processingTimeoutLatch = new CountDownLatch(1);
122 122 pendingMap.forEach((id, msg) -> {
123   - log.info("[{}] Creating main callback for message: {}", id, msg.getValue());
124   - TbMsgCallback callback = new MsgPackCallback<>(id, processingTimeoutLatch, pendingMap, new ConcurrentHashMap<>(), failedMap);
  123 + log.trace("[{}] Creating main callback for message: {}", id, msg.getValue());
  124 + TbCallback callback = new TbPackCallback<>(id, processingTimeoutLatch, pendingMap, failedMap);
125 125 try {
126 126 ToCoreMsg toCoreMsg = msg.getValue();
127 127 if (toCoreMsg.hasToSubscriptionMgrMsg()) {
... ... @@ -182,7 +182,7 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService<ToCore
182 182 }
183 183
184 184 @Override
185   - protected void handleNotification(UUID id, TbProtoQueueMsg<ToCoreNotificationMsg> msg, TbMsgCallback callback) {
  185 + protected void handleNotification(UUID id, TbProtoQueueMsg<ToCoreNotificationMsg> msg, TbCallback callback) {
186 186 ToCoreNotificationMsg toCoreMsg = msg.getValue();
187 187 if (toCoreMsg.hasToLocalSubscriptionServiceMsg()) {
188 188 log.trace("[{}] Forwarding message to local subscription service {}", id, toCoreMsg.getToLocalSubscriptionServiceMsg());
... ... @@ -200,7 +200,7 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService<ToCore
200 200 }
201 201 }
202 202
203   - private void forwardToCoreRpcService(FromDeviceRPCResponseProto proto, TbMsgCallback callback) {
  203 + private void forwardToCoreRpcService(FromDeviceRPCResponseProto proto, TbCallback callback) {
204 204 RpcError error = proto.getError() > 0 ? RpcError.values()[proto.getError()] : null;
205 205 FromDeviceRpcResponse response = new FromDeviceRpcResponse(new UUID(proto.getRequestIdMSB(), proto.getRequestIdLSB())
206 206 , proto.getResponse(), error);
... ... @@ -215,7 +215,7 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService<ToCore
215 215 }
216 216 }
217 217
218   - private void forwardToLocalSubMgrService(LocalSubscriptionServiceMsgProto msg, TbMsgCallback callback) {
  218 + private void forwardToLocalSubMgrService(LocalSubscriptionServiceMsgProto msg, TbCallback callback) {
219 219 if (msg.hasSubUpdate()) {
220 220 localSubscriptionService.onSubscriptionUpdate(msg.getSubUpdate().getSessionId(), TbSubscriptionUtils.fromProto(msg.getSubUpdate()), callback);
221 221 } else {
... ... @@ -223,7 +223,7 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService<ToCore
223 223 }
224 224 }
225 225
226   - private void forwardToSubMgrService(SubscriptionMgrMsgProto msg, TbMsgCallback callback) {
  226 + private void forwardToSubMgrService(SubscriptionMgrMsgProto msg, TbCallback callback) {
227 227 if (msg.hasAttributeSub()) {
228 228 subscriptionManagerService.addSubscription(TbSubscriptionUtils.fromProto(msg.getAttributeSub()), callback);
229 229 } else if (msg.hasTelemetrySub()) {
... ... @@ -248,21 +248,21 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService<ToCore
248 248 }
249 249 }
250 250
251   - private void forwardToStateService(DeviceStateServiceMsgProto deviceStateServiceMsg, TbMsgCallback callback) {
  251 + private void forwardToStateService(DeviceStateServiceMsgProto deviceStateServiceMsg, TbCallback callback) {
252 252 if (statsEnabled) {
253 253 stats.log(deviceStateServiceMsg);
254 254 }
255 255 stateService.onQueueMsg(deviceStateServiceMsg, callback);
256 256 }
257 257
258   - private void forwardToDeviceActor(TransportToDeviceActorMsg toDeviceActorMsg, TbMsgCallback callback) {
  258 + private void forwardToDeviceActor(TransportToDeviceActorMsg toDeviceActorMsg, TbCallback callback) {
259 259 if (statsEnabled) {
260 260 stats.log(toDeviceActorMsg);
261 261 }
262 262 actorContext.getAppActor().tell(new TransportToDeviceActorMsgWrapper(toDeviceActorMsg, callback), ActorRef.noSender());
263 263 }
264 264
265   - private void throwNotHandled(Object msg, TbMsgCallback callback) {
  265 + private void throwNotHandled(Object msg, TbCallback callback) {
266 266 log.warn("Message not handled: {}", msg);
267 267 callback.onFailure(new RuntimeException("Message not handled!"));
268 268 }
... ...
... ... @@ -27,8 +27,11 @@ import org.thingsboard.server.common.data.id.TenantId;
27 27 import org.thingsboard.server.common.msg.TbActorMsg;
28 28 import org.thingsboard.server.common.msg.TbMsg;
29 29 import org.thingsboard.server.common.msg.queue.QueueToRuleEngineMsg;
  30 +import org.thingsboard.server.common.msg.queue.RuleEngineException;
  31 +import org.thingsboard.server.common.msg.queue.RuleNodeException;
30 32 import org.thingsboard.server.common.msg.queue.ServiceQueue;
31 33 import org.thingsboard.server.common.msg.queue.ServiceType;
  34 +import org.thingsboard.server.common.msg.queue.TbCallback;
32 35 import org.thingsboard.server.common.msg.queue.TbMsgCallback;
33 36 import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg;
34 37 import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineNotificationMsg;
... ... @@ -45,6 +48,7 @@ import org.thingsboard.server.service.queue.processing.TbRuleEngineProcessingDec
45 48 import org.thingsboard.server.service.queue.processing.TbRuleEngineProcessingResult;
46 49 import org.thingsboard.server.service.queue.processing.TbRuleEngineProcessingStrategy;
47 50 import org.thingsboard.server.service.queue.processing.TbRuleEngineProcessingStrategyFactory;
  51 +import org.thingsboard.server.service.stats.RuleEngineStatisticsService;
48 52
49 53 import javax.annotation.PostConstruct;
50 54 import java.util.Collections;
... ... @@ -69,20 +73,22 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService<
69 73 private long pollDuration;
70 74 @Value("${queue.rule-engine.pack-processing-timeout}")
71 75 private long packProcessingTimeout;
72   - @Value("${queue.rule-engine.stats.enabled:false}")
  76 + @Value("${queue.rule-engine.stats.enabled:true}")
73 77 private boolean statsEnabled;
74 78
75   - private final TbCoreConsumerStats stats = new TbCoreConsumerStats();
76 79 private final TbRuleEngineProcessingStrategyFactory factory;
77 80 private final TbRuleEngineQueueFactory tbRuleEngineQueueFactory;
78 81 private final TbQueueRuleEngineSettings ruleEngineSettings;
  82 + private final RuleEngineStatisticsService statisticsService;
79 83 private final ConcurrentMap<String, TbQueueConsumer<TbProtoQueueMsg<ToRuleEngineMsg>>> consumers = new ConcurrentHashMap<>();
80 84 private final ConcurrentMap<String, TbRuleEngineQueueConfiguration> consumerConfigurations = new ConcurrentHashMap<>();
  85 + private final ConcurrentMap<String, TbRuleEngineConsumerStats> consumerStats = new ConcurrentHashMap<>();
81 86
82 87 public DefaultTbRuleEngineConsumerService(TbRuleEngineProcessingStrategyFactory factory, TbQueueRuleEngineSettings ruleEngineSettings,
83   - TbRuleEngineQueueFactory tbRuleEngineQueueFactory,
  88 + TbRuleEngineQueueFactory tbRuleEngineQueueFactory, RuleEngineStatisticsService statisticsService,
84 89 ActorSystemContext actorContext, DataDecodingEncodingService encodingService) {
85 90 super(actorContext, encodingService, tbRuleEngineQueueFactory.createToRuleEngineNotificationsMsgConsumer());
  91 + this.statisticsService = statisticsService;
86 92 this.ruleEngineSettings = ruleEngineSettings;
87 93 this.tbRuleEngineQueueFactory = tbRuleEngineQueueFactory;
88 94 this.factory = factory;
... ... @@ -92,7 +98,9 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService<
92 98 public void init() {
93 99 super.init("tb-rule-engine-consumer", "tb-rule-engine-notifications-consumer");
94 100 for (TbRuleEngineQueueConfiguration configuration : ruleEngineSettings.getQueues()) {
  101 + consumerConfigurations.putIfAbsent(configuration.getName(), configuration);
95 102 consumers.computeIfAbsent(configuration.getName(), queueName -> tbRuleEngineQueueFactory.createToRuleEngineMsgConsumer(configuration));
  103 + consumerStats.put(configuration.getName(), new TbRuleEngineConsumerStats(configuration.getName()));
96 104 }
97 105 }
98 106
... ... @@ -107,7 +115,7 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService<
107 115
108 116 @Override
109 117 protected void launchMainConsumers() {
110   - consumers.forEach((queue, consumer) -> launchConsumer(consumer, consumerConfigurations.get(queue)));
  118 + consumers.forEach((queue, consumer) -> launchConsumer(consumer, consumerConfigurations.get(queue), consumerStats.get(queue)));
111 119 }
112 120
113 121 @Override
... ... @@ -115,7 +123,7 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService<
115 123 consumers.values().forEach(TbQueueConsumer::unsubscribe);
116 124 }
117 125
118   - private void launchConsumer(TbQueueConsumer<TbProtoQueueMsg<ToRuleEngineMsg>> consumer, TbRuleEngineQueueConfiguration configuration) {
  126 + private void launchConsumer(TbQueueConsumer<TbProtoQueueMsg<ToRuleEngineMsg>> consumer, TbRuleEngineQueueConfiguration configuration, TbRuleEngineConsumerStats stats) {
119 127 consumersExecutor.execute(() -> {
120 128 while (!stopped) {
121 129 try {
... ... @@ -123,7 +131,7 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService<
123 131 if (msgs.isEmpty()) {
124 132 continue;
125 133 }
126   - TbRuleEngineProcessingStrategy strategy = factory.newInstance(configuration.getAckStrategy());
  134 + TbRuleEngineProcessingStrategy strategy = factory.newInstance(configuration.getName(), configuration.getAckStrategy());
127 135 TbRuleEngineProcessingDecision decision = null;
128 136 boolean firstAttempt = true;
129 137 while (!stopped && (firstAttempt || !decision.isCommit())) {
... ... @@ -137,21 +145,21 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService<
137 145 }
138 146 ConcurrentMap<UUID, TbProtoQueueMsg<ToRuleEngineMsg>> successMap = new ConcurrentHashMap<>();
139 147 ConcurrentMap<UUID, TbProtoQueueMsg<ToRuleEngineMsg>> failedMap = new ConcurrentHashMap<>();
140   -
  148 + ConcurrentMap<TenantId, RuleEngineException> exceptionsMap = new ConcurrentHashMap<>();
141 149 CountDownLatch processingTimeoutLatch = new CountDownLatch(1);
142 150 allMap.forEach((id, msg) -> {
143   - log.info("[{}] Creating main callback for message: {}", id, msg.getValue());
144   - TbMsgCallback callback = new MsgPackCallback<>(id, processingTimeoutLatch, allMap, successMap, failedMap);
  151 + log.trace("[{}] Creating main callback for message: {}", id, msg.getValue());
  152 + ToRuleEngineMsg toRuleEngineMsg = msg.getValue();
  153 + TenantId tenantId = new TenantId(new UUID(toRuleEngineMsg.getTenantIdMSB(), toRuleEngineMsg.getTenantIdLSB()));
  154 + TbMsgCallback callback = new TbMsgPackCallback<>(id, tenantId, processingTimeoutLatch, allMap, successMap, failedMap, exceptionsMap);
145 155 try {
146   - ToRuleEngineMsg toRuleEngineMsg = msg.getValue();
147   - TenantId tenantId = new TenantId(new UUID(toRuleEngineMsg.getTenantIdMSB(), toRuleEngineMsg.getTenantIdLSB()));
148 156 if (toRuleEngineMsg.getTbMsg() != null && !toRuleEngineMsg.getTbMsg().isEmpty()) {
149 157 forwardToRuleEngineActor(tenantId, toRuleEngineMsg, callback);
150 158 } else {
151 159 callback.onSuccess();
152 160 }
153   - } catch (Throwable e) {
154   - callback.onFailure(e);
  161 + } catch (Exception e) {
  162 + callback.onFailure(new RuleEngineException(e.getMessage()));
155 163 }
156 164 });
157 165
... ... @@ -159,7 +167,11 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService<
159 167 if (!processingTimeoutLatch.await(packProcessingTimeout, TimeUnit.MILLISECONDS)) {
160 168 timeout = true;
161 169 }
162   - decision = strategy.analyze(new TbRuleEngineProcessingResult(timeout, allMap, successMap, failedMap));
  170 + TbRuleEngineProcessingResult result = new TbRuleEngineProcessingResult(timeout, allMap, successMap, failedMap, exceptionsMap);
  171 + decision = strategy.analyze(result);
  172 + if (statsEnabled) {
  173 + stats.log(result, decision.isCommit());
  174 + }
163 175 }
164 176 consumer.commit();
165 177 } catch (Exception e) {
... ... @@ -193,7 +205,7 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService<
193 205 }
194 206
195 207 @Override
196   - protected void handleNotification(UUID id, TbProtoQueueMsg<ToRuleEngineNotificationMsg> msg, TbMsgCallback callback) throws Exception {
  208 + protected void handleNotification(UUID id, TbProtoQueueMsg<ToRuleEngineNotificationMsg> msg, TbCallback callback) throws Exception {
197 209 ToRuleEngineNotificationMsg nfMsg = msg.getValue();
198 210 if (nfMsg.getComponentLifecycleMsg() != null && !nfMsg.getComponentLifecycleMsg().isEmpty()) {
199 211 Optional<TbActorMsg> actorMsg = encodingService.decode(nfMsg.getComponentLifecycleMsg().toByteArray());
... ... @@ -219,18 +231,18 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService<
219 231 relationTypes = new HashSet<>(relationTypesList);
220 232 }
221 233 }
222   - msg = new QueueToRuleEngineMsg(tenantId, tbMsg, relationTypes);
  234 + msg = new QueueToRuleEngineMsg(tenantId, tbMsg, relationTypes, toRuleEngineMsg.getFailureMessage());
223 235 actorContext.getAppActor().tell(msg, ActorRef.noSender());
224   - //TODO: 2.5 before release.
225   -// if (statsEnabled) {
226   -// stats.log(toDeviceActorMsg);
227   -// }
228 236 }
229 237
230 238 @Scheduled(fixedDelayString = "${queue.rule-engine.stats.print-interval-ms}")
231 239 public void printStats() {
232 240 if (statsEnabled) {
233   - stats.printStats();
  241 + long ts = System.currentTimeMillis();
  242 + consumerStats.forEach((queue, stats) -> {
  243 + stats.printStats();
  244 + statisticsService.reportQueueStats(ts, stats);
  245 + });
234 246 }
235 247 }
236 248
... ...
  1 +/**
  2 + * Copyright © 2016-2020 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.service.queue;
  17 +
  18 +import lombok.extern.slf4j.Slf4j;
  19 +import org.thingsboard.server.common.data.id.TenantId;
  20 +import org.thingsboard.server.common.msg.queue.RuleEngineException;
  21 +import org.thingsboard.server.common.msg.queue.RuleNodeException;
  22 +import org.thingsboard.server.common.msg.queue.TbCallback;
  23 +import org.thingsboard.server.common.msg.queue.TbMsgCallback;
  24 +
  25 +import java.util.UUID;
  26 +import java.util.concurrent.ConcurrentMap;
  27 +import java.util.concurrent.CountDownLatch;
  28 +
  29 +@Slf4j
  30 +public class TbMsgPackCallback<T> implements TbMsgCallback {
  31 + private final CountDownLatch processingTimeoutLatch;
  32 + private final ConcurrentMap<UUID, T> ackMap;
  33 + private final ConcurrentMap<UUID, T> successMap;
  34 + private final ConcurrentMap<UUID, T> failedMap;
  35 + private final UUID id;
  36 + private final TenantId tenantId;
  37 + private final ConcurrentMap<TenantId, RuleEngineException> firstExceptions;
  38 +
  39 + public TbMsgPackCallback(UUID id, TenantId tenantId,
  40 + CountDownLatch processingTimeoutLatch,
  41 + ConcurrentMap<UUID, T> ackMap,
  42 + ConcurrentMap<UUID, T> successMap,
  43 + ConcurrentMap<UUID, T> failedMap,
  44 + ConcurrentMap<TenantId, RuleEngineException> firstExceptions) {
  45 + this.id = id;
  46 + this.tenantId = tenantId;
  47 + this.processingTimeoutLatch = processingTimeoutLatch;
  48 + this.ackMap = ackMap;
  49 + this.successMap = successMap;
  50 + this.failedMap = failedMap;
  51 + this.firstExceptions = firstExceptions;
  52 + }
  53 +
  54 + @Override
  55 + public void onSuccess() {
  56 + log.trace("[{}] ON SUCCESS", id);
  57 + T msg = ackMap.remove(id);
  58 + if (msg != null) {
  59 + successMap.put(id, msg);
  60 + }
  61 + if (msg != null && ackMap.isEmpty()) {
  62 + processingTimeoutLatch.countDown();
  63 + }
  64 + }
  65 +
  66 + @Override
  67 + public void onFailure(RuleEngineException e) {
  68 + log.trace("[{}] ON FAILURE", id, e);
  69 + T msg = ackMap.remove(id);
  70 + if (msg != null) {
  71 + failedMap.put(id, msg);
  72 + firstExceptions.putIfAbsent(tenantId, e);
  73 + }
  74 + if (ackMap.isEmpty()) {
  75 + processingTimeoutLatch.countDown();
  76 + }
  77 + }
  78 +}
... ...
application/src/main/java/org/thingsboard/server/service/queue/TbPackCallback.java renamed from application/src/main/java/org/thingsboard/server/service/queue/MsgPackCallback.java
... ... @@ -16,30 +16,26 @@
16 16 package org.thingsboard.server.service.queue;
17 17
18 18 import lombok.extern.slf4j.Slf4j;
19   -import org.thingsboard.server.common.msg.queue.TbMsgCallback;
20   -import org.thingsboard.server.queue.common.TbProtoQueueMsg;
  19 +import org.thingsboard.server.common.msg.queue.TbCallback;
21 20
22 21 import java.util.UUID;
23   -import java.util.concurrent.ConcurrentHashMap;
24 22 import java.util.concurrent.ConcurrentMap;
25 23 import java.util.concurrent.CountDownLatch;
26 24
27 25 @Slf4j
28   -public class MsgPackCallback<T> implements TbMsgCallback {
  26 +public class TbPackCallback<T> implements TbCallback {
29 27 private final CountDownLatch processingTimeoutLatch;
30 28 private final ConcurrentMap<UUID, T> ackMap;
31   - private final ConcurrentMap<UUID, T> successMap;
32 29 private final ConcurrentMap<UUID, T> failedMap;
33 30 private final UUID id;
34 31
35   - public MsgPackCallback(UUID id, CountDownLatch processingTimeoutLatch,
36   - ConcurrentMap<UUID, T> ackMap,
37   - ConcurrentMap<UUID, T> successMap,
38   - ConcurrentMap<UUID, T> failedMap) {
  32 + public TbPackCallback(UUID id,
  33 + CountDownLatch processingTimeoutLatch,
  34 + ConcurrentMap<UUID, T> ackMap,
  35 + ConcurrentMap<UUID, T> failedMap) {
39 36 this.id = id;
40 37 this.processingTimeoutLatch = processingTimeoutLatch;
41 38 this.ackMap = ackMap;
42   - this.successMap = successMap;
43 39 this.failedMap = failedMap;
44 40 }
45 41
... ... @@ -47,9 +43,6 @@ public class MsgPackCallback<T> implements TbMsgCallback {
47 43 public void onSuccess() {
48 44 log.trace("[{}] ON SUCCESS", id);
49 45 T msg = ackMap.remove(id);
50   - if (msg != null) {
51   - successMap.put(id, msg);
52   - }
53 46 if (msg != null && ackMap.isEmpty()) {
54 47 processingTimeoutLatch.countDown();
55 48 }
... ... @@ -57,7 +50,7 @@ public class MsgPackCallback<T> implements TbMsgCallback {
57 50
58 51 @Override
59 52 public void onFailure(Throwable t) {
60   - log.trace("[{}] ON FAILURE", id);
  53 + log.trace("[{}] ON FAILURE", id, t);
61 54 T msg = ackMap.remove(id);
62 55 if (msg != null) {
63 56 failedMap.put(id, msg);
... ...
... ... @@ -15,38 +15,119 @@
15 15 */
16 16 package org.thingsboard.server.service.queue;
17 17
  18 +import lombok.Data;
18 19 import lombok.extern.slf4j.Slf4j;
19   -import org.thingsboard.server.gen.transport.TransportProtos;
  20 +import org.thingsboard.server.common.data.id.TenantId;
  21 +import org.thingsboard.server.common.msg.queue.RuleEngineException;
  22 +import org.thingsboard.server.common.msg.queue.RuleNodeException;
  23 +import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg;
  24 +import org.thingsboard.server.queue.common.TbProtoQueueMsg;
  25 +import org.thingsboard.server.service.queue.processing.TbRuleEngineProcessingResult;
20 26
  27 +import java.util.HashMap;
  28 +import java.util.Map;
  29 +import java.util.UUID;
  30 +import java.util.concurrent.ConcurrentHashMap;
  31 +import java.util.concurrent.ConcurrentMap;
21 32 import java.util.concurrent.atomic.AtomicInteger;
22 33
23 34 @Slf4j
  35 +@Data
24 36 public class TbRuleEngineConsumerStats {
25 37
26   - private final AtomicInteger totalCounter = new AtomicInteger(0);
27   - private final AtomicInteger postTelemetryCounter = new AtomicInteger(0);
28   - private final AtomicInteger postAttributesCounter = new AtomicInteger(0);
29   - private final AtomicInteger toServerRPCCallRequestCounter = new AtomicInteger(0);
  38 + public static final String TOTAL_MSGS = "totalMsgs";
  39 + public static final String SUCCESSFUL_MSGS = "successfulMsgs";
  40 + public static final String TMP_TIMEOUT = "tmpTimeout";
  41 + public static final String TMP_FAILED = "tmpFailed";
  42 + public static final String TIMEOUT_MSGS = "timeoutMsgs";
  43 + public static final String FAILED_MSGS = "failedMsgs";
  44 + public static final String SUCCESSFUL_ITERATIONS = "successfulIterations";
  45 + public static final String FAILED_ITERATIONS = "failedIterations";
30 46
31   - public void log(TransportProtos.TransportToRuleEngineMsg msg) {
32   - totalCounter.incrementAndGet();
33   - if (msg.hasPostTelemetry()) {
34   - postTelemetryCounter.incrementAndGet();
35   - }
36   - if (msg.hasPostAttributes()) {
37   - postAttributesCounter.incrementAndGet();
38   - }
39   - if (msg.hasToServerRPCCallRequest()) {
40   - toServerRPCCallRequestCounter.incrementAndGet();
  47 + private final AtomicInteger totalMsgCounter = new AtomicInteger(0);
  48 + private final AtomicInteger successMsgCounter = new AtomicInteger(0);
  49 + private final AtomicInteger tmpTimeoutMsgCounter = new AtomicInteger(0);
  50 + private final AtomicInteger tmpFailedMsgCounter = new AtomicInteger(0);
  51 +
  52 + private final AtomicInteger timeoutMsgCounter = new AtomicInteger(0);
  53 + private final AtomicInteger failedMsgCounter = new AtomicInteger(0);
  54 +
  55 + private final AtomicInteger successIterationsCounter = new AtomicInteger(0);
  56 + private final AtomicInteger failedIterationsCounter = new AtomicInteger(0);
  57 +
  58 + private final Map<String, AtomicInteger> counters = new HashMap<>();
  59 + private final ConcurrentMap<UUID, TbTenantRuleEngineStats> tenantStats = new ConcurrentHashMap<>();
  60 + private final ConcurrentMap<TenantId, RuleEngineException> tenantExceptions = new ConcurrentHashMap<>();
  61 +
  62 + private final String queueName;
  63 +
  64 + public TbRuleEngineConsumerStats(String queueName) {
  65 + this.queueName = queueName;
  66 + counters.put(TOTAL_MSGS, totalMsgCounter);
  67 + counters.put(SUCCESSFUL_MSGS, successMsgCounter);
  68 + counters.put(TIMEOUT_MSGS, timeoutMsgCounter);
  69 + counters.put(FAILED_MSGS, failedMsgCounter);
  70 +
  71 + counters.put(TMP_TIMEOUT, tmpTimeoutMsgCounter);
  72 + counters.put(TMP_FAILED, tmpFailedMsgCounter);
  73 + counters.put(SUCCESSFUL_ITERATIONS, successIterationsCounter);
  74 + counters.put(FAILED_ITERATIONS, failedIterationsCounter);
  75 + }
  76 +
  77 + public void log(TbRuleEngineProcessingResult msg, boolean finalIterationForPack) {
  78 + int success = msg.getSuccessMap().size();
  79 + int pending = msg.getPendingMap().size();
  80 + int failed = msg.getFailureMap().size();
  81 + totalMsgCounter.addAndGet(success + pending + failed);
  82 + successMsgCounter.addAndGet(success);
  83 + msg.getSuccessMap().values().forEach(m -> getTenantStats(m).logSuccess());
  84 + if (finalIterationForPack) {
  85 + if (pending > 0 || failed > 0) {
  86 + timeoutMsgCounter.addAndGet(pending);
  87 + failedMsgCounter.addAndGet(failed);
  88 + if (pending > 0) {
  89 + msg.getPendingMap().values().forEach(m -> getTenantStats(m).logTimeout());
  90 + }
  91 + if (failed > 0) {
  92 + msg.getFailureMap().values().forEach(m -> getTenantStats(m).logFailed());
  93 + }
  94 + failedIterationsCounter.incrementAndGet();
  95 + } else {
  96 + successIterationsCounter.incrementAndGet();
  97 + }
  98 + } else {
  99 + failedIterationsCounter.incrementAndGet();
  100 + tmpTimeoutMsgCounter.addAndGet(pending);
  101 + tmpFailedMsgCounter.addAndGet(failed);
  102 + if (pending > 0) {
  103 + msg.getPendingMap().values().forEach(m -> getTenantStats(m).logTmpTimeout());
  104 + }
  105 + if (failed > 0) {
  106 + msg.getFailureMap().values().forEach(m -> getTenantStats(m).logTmpFailed());
  107 + }
41 108 }
  109 + msg.getExceptionsMap().forEach(tenantExceptions::putIfAbsent);
  110 + }
  111 +
  112 + private TbTenantRuleEngineStats getTenantStats(TbProtoQueueMsg<ToRuleEngineMsg> m) {
  113 + ToRuleEngineMsg reMsg = m.getValue();
  114 + return tenantStats.computeIfAbsent(new UUID(reMsg.getTenantIdMSB(), reMsg.getTenantIdLSB()), TbTenantRuleEngineStats::new);
42 115 }
43 116
44 117 public void printStats() {
45   - int total = totalCounter.getAndSet(0);
  118 + int total = totalMsgCounter.get();
46 119 if (total > 0) {
47   - log.info("Transport total [{}] telemetry [{}] attributes [{}] toServerRpc [{}]",
48   - total, postTelemetryCounter.getAndSet(0),
49   - postAttributesCounter.getAndSet(0), toServerRPCCallRequestCounter.getAndSet(0));
  120 + StringBuilder stats = new StringBuilder();
  121 + counters.forEach((label, value) -> {
  122 + stats.append(label).append(" = [").append(value.get()).append("] ");
  123 + });
  124 + log.info("[{}] Stats: {}", queueName, stats);
50 125 }
51 126 }
  127 +
  128 + public void reset() {
  129 + counters.values().forEach(counter -> counter.set(0));
  130 + tenantStats.clear();
  131 + tenantExceptions.clear();
  132 + }
52 133 }
... ...
  1 +/**
  2 + * Copyright © 2016-2020 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.service.queue;
  17 +
  18 +import lombok.Data;
  19 +import lombok.extern.slf4j.Slf4j;
  20 +
  21 +import java.util.HashMap;
  22 +import java.util.Map;
  23 +import java.util.UUID;
  24 +import java.util.concurrent.atomic.AtomicInteger;
  25 +
  26 +@Slf4j
  27 +@Data
  28 +public class TbTenantRuleEngineStats {
  29 +
  30 + private final UUID tenantId;
  31 +
  32 + private final AtomicInteger totalMsgCounter = new AtomicInteger(0);
  33 + private final AtomicInteger successMsgCounter = new AtomicInteger(0);
  34 + private final AtomicInteger tmpTimeoutMsgCounter = new AtomicInteger(0);
  35 + private final AtomicInteger tmpFailedMsgCounter = new AtomicInteger(0);
  36 +
  37 + private final AtomicInteger timeoutMsgCounter = new AtomicInteger(0);
  38 + private final AtomicInteger failedMsgCounter = new AtomicInteger(0);
  39 +
  40 + private final Map<String, AtomicInteger> counters = new HashMap<>();
  41 +
  42 + public TbTenantRuleEngineStats(UUID tenantId) {
  43 + this.tenantId = tenantId;
  44 + counters.put(TbRuleEngineConsumerStats.TOTAL_MSGS, totalMsgCounter);
  45 + counters.put(TbRuleEngineConsumerStats.SUCCESSFUL_MSGS, successMsgCounter);
  46 + counters.put(TbRuleEngineConsumerStats.TIMEOUT_MSGS, timeoutMsgCounter);
  47 + counters.put(TbRuleEngineConsumerStats.FAILED_MSGS, failedMsgCounter);
  48 +
  49 + counters.put(TbRuleEngineConsumerStats.TMP_TIMEOUT, tmpTimeoutMsgCounter);
  50 + counters.put(TbRuleEngineConsumerStats.TMP_FAILED, tmpFailedMsgCounter);
  51 + }
  52 +
  53 + public void logSuccess() {
  54 + totalMsgCounter.incrementAndGet();
  55 + successMsgCounter.incrementAndGet();
  56 + }
  57 +
  58 + public void logFailed() {
  59 + totalMsgCounter.incrementAndGet();
  60 + failedMsgCounter.incrementAndGet();
  61 + }
  62 +
  63 + public void logTimeout() {
  64 + totalMsgCounter.incrementAndGet();
  65 + timeoutMsgCounter.incrementAndGet();
  66 + }
  67 +
  68 + public void logTmpFailed() {
  69 + totalMsgCounter.incrementAndGet();
  70 + tmpFailedMsgCounter.incrementAndGet();
  71 + }
  72 +
  73 + public void logTmpTimeout() {
  74 + totalMsgCounter.incrementAndGet();
  75 + tmpTimeoutMsgCounter.incrementAndGet();
  76 + }
  77 +
  78 + public void printStats() {
  79 + int total = totalMsgCounter.get();
  80 + if (total > 0) {
  81 + StringBuilder stats = new StringBuilder();
  82 + counters.forEach((label, value) -> {
  83 + stats.append(label).append(" = [").append(value.get()).append("]");
  84 + });
  85 + log.info("[{}] Stats: {}", tenantId, stats);
  86 + }
  87 + }
  88 +
  89 + public void reset() {
  90 + counters.values().forEach(counter -> counter.set(0));
  91 + }
  92 +}
... ...
... ... @@ -22,12 +22,12 @@ import org.springframework.context.event.EventListener;
22 22 import org.thingsboard.common.util.ThingsBoardThreadFactory;
23 23 import org.thingsboard.server.actors.ActorSystemContext;
24 24 import org.thingsboard.server.common.msg.queue.ServiceType;
25   -import org.thingsboard.server.common.msg.queue.TbMsgCallback;
  25 +import org.thingsboard.server.common.msg.queue.TbCallback;
26 26 import org.thingsboard.server.queue.TbQueueConsumer;
27 27 import org.thingsboard.server.queue.common.TbProtoQueueMsg;
28 28 import org.thingsboard.server.queue.discovery.PartitionChangeEvent;
29 29 import org.thingsboard.server.service.encoding.DataDecodingEncodingService;
30   -import org.thingsboard.server.service.queue.MsgPackCallback;
  30 +import org.thingsboard.server.service.queue.TbPackCallback;
31 31
32 32 import javax.annotation.PreDestroy;
33 33 import java.util.List;
... ... @@ -95,8 +95,8 @@ public abstract class AbstractConsumerService<N extends com.google.protobuf.Gene
95 95 ConcurrentMap<UUID, TbProtoQueueMsg<N>> failedMap = new ConcurrentHashMap<>();
96 96 CountDownLatch processingTimeoutLatch = new CountDownLatch(1);
97 97 pendingMap.forEach((id, msg) -> {
98   - log.info("[{}] Creating notification callback for message: {}", id, msg.getValue());
99   - TbMsgCallback callback = new MsgPackCallback<>(id, processingTimeoutLatch, pendingMap, new ConcurrentHashMap<>(), failedMap);
  98 + log.trace("[{}] Creating notification callback for message: {}", id, msg.getValue());
  99 + TbCallback callback = new TbPackCallback<>(id, processingTimeoutLatch, pendingMap, failedMap);
100 100 try {
101 101 handleNotification(id, msg, callback);
102 102 } catch (Throwable e) {
... ... @@ -124,7 +124,7 @@ public abstract class AbstractConsumerService<N extends com.google.protobuf.Gene
124 124 });
125 125 }
126 126
127   - protected abstract void handleNotification(UUID id, TbProtoQueueMsg<N> msg, TbMsgCallback callback) throws Exception;
  127 + protected abstract void handleNotification(UUID id, TbProtoQueueMsg<N> msg, TbCallback callback) throws Exception;
128 128
129 129 @PreDestroy
130 130 public void destroy() {
... ...
... ... @@ -16,6 +16,8 @@
16 16 package org.thingsboard.server.service.queue.processing;
17 17
18 18 import lombok.Getter;
  19 +import org.thingsboard.server.common.data.id.TenantId;
  20 +import org.thingsboard.server.common.msg.queue.RuleEngineException;
19 21 import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg;
20 22 import org.thingsboard.server.queue.common.TbProtoQueueMsg;
21 23
... ... @@ -25,24 +27,28 @@ import java.util.concurrent.ConcurrentMap;
25 27 public class TbRuleEngineProcessingResult {
26 28
27 29 @Getter
28   - private boolean success;
  30 + private final boolean success;
29 31 @Getter
30   - private boolean timeout;
  32 + private final boolean timeout;
31 33 @Getter
32   - private ConcurrentMap<UUID, TbProtoQueueMsg<ToRuleEngineMsg>> pendingMap;
  34 + private final ConcurrentMap<UUID, TbProtoQueueMsg<ToRuleEngineMsg>> pendingMap;
33 35 @Getter
34   - private ConcurrentMap<UUID, TbProtoQueueMsg<ToRuleEngineMsg>> successMap;
  36 + private final ConcurrentMap<UUID, TbProtoQueueMsg<ToRuleEngineMsg>> successMap;
35 37 @Getter
36   - private ConcurrentMap<UUID, TbProtoQueueMsg<ToRuleEngineMsg>> failureMap;
  38 + private final ConcurrentMap<UUID, TbProtoQueueMsg<ToRuleEngineMsg>> failureMap;
  39 + @Getter
  40 + private final ConcurrentMap<TenantId, RuleEngineException> exceptionsMap;
37 41
38 42 public TbRuleEngineProcessingResult(boolean timeout,
39 43 ConcurrentMap<UUID, TbProtoQueueMsg<ToRuleEngineMsg>> pendingMap,
40 44 ConcurrentMap<UUID, TbProtoQueueMsg<ToRuleEngineMsg>> successMap,
41   - ConcurrentMap<UUID, TbProtoQueueMsg<ToRuleEngineMsg>> failureMap) {
  45 + ConcurrentMap<UUID, TbProtoQueueMsg<ToRuleEngineMsg>> failureMap,
  46 + ConcurrentMap<TenantId, RuleEngineException> exceptionsMap) {
42 47 this.timeout = timeout;
43 48 this.pendingMap = pendingMap;
44 49 this.successMap = successMap;
45 50 this.failureMap = failureMap;
  51 + this.exceptionsMap = exceptionsMap;
46 52 this.success = !timeout && pendingMap.isEmpty() && failureMap.isEmpty();
47 53 }
48 54 }
... ...
... ... @@ -32,24 +32,25 @@ import java.util.concurrent.TimeUnit;
32 32 @Slf4j
33 33 public class TbRuleEngineProcessingStrategyFactory {
34 34
35   - public TbRuleEngineProcessingStrategy newInstance(TbRuleEngineQueueAckStrategyConfiguration configuration) {
  35 + public TbRuleEngineProcessingStrategy newInstance(String name, TbRuleEngineQueueAckStrategyConfiguration configuration) {
36 36 switch (configuration.getType()) {
37 37 case "SKIP_ALL":
38   - return new SkipStrategy();
  38 + return new SkipStrategy(name);
39 39 case "RETRY_ALL":
40   - return new RetryStrategy(true, true, true, configuration);
  40 + return new RetryStrategy(name, true, true, true, configuration);
41 41 case "RETRY_FAILED":
42   - return new RetryStrategy(false, true, false, configuration);
  42 + return new RetryStrategy(name, false, true, false, configuration);
43 43 case "RETRY_TIMED_OUT":
44   - return new RetryStrategy(false, false, true, configuration);
  44 + return new RetryStrategy(name, false, false, true, configuration);
45 45 case "RETRY_FAILED_AND_TIMED_OUT":
46   - return new RetryStrategy(false, true, true, configuration);
  46 + return new RetryStrategy(name, false, true, true, configuration);
47 47 default:
48 48 throw new RuntimeException("TbRuleEngineProcessingStrategy with type " + configuration.getType() + " is not supported!");
49 49 }
50 50 }
51 51
52 52 private static class RetryStrategy implements TbRuleEngineProcessingStrategy {
  53 + private final String queueName;
53 54 private final boolean retrySuccessful;
54 55 private final boolean retryFailed;
55 56 private final boolean retryTimeout;
... ... @@ -60,7 +61,8 @@ public class TbRuleEngineProcessingStrategyFactory {
60 61 private int initialTotalCount;
61 62 private int retryCount;
62 63
63   - public RetryStrategy(boolean retrySuccessful, boolean retryFailed, boolean retryTimeout, TbRuleEngineQueueAckStrategyConfiguration configuration) {
  64 + public RetryStrategy(String queueName, boolean retrySuccessful, boolean retryFailed, boolean retryTimeout, TbRuleEngineQueueAckStrategyConfiguration configuration) {
  65 + this.queueName = queueName;
64 66 this.retrySuccessful = retrySuccessful;
65 67 this.retryFailed = retryFailed;
66 68 this.retryTimeout = retryTimeout;
... ... @@ -80,10 +82,10 @@ public class TbRuleEngineProcessingStrategyFactory {
80 82 retryCount++;
81 83 double failedCount = result.getFailureMap().size() + result.getPendingMap().size();
82 84 if (maxRetries > 0 && retryCount > maxRetries) {
83   - log.info("Skip reprocess of the rule engine pack due to max retries");
  85 + log.info("[{}] Skip reprocess of the rule engine pack due to max retries", queueName);
84 86 return new TbRuleEngineProcessingDecision(true, null);
85 87 } else if (maxAllowedFailurePercentage > 0 && (failedCount / initialTotalCount) > maxAllowedFailurePercentage) {
86   - log.info("Skip reprocess of the rule engine pack due to max allowed failure percentage");
  88 + log.info("[{}] Skip reprocess of the rule engine pack due to max allowed failure percentage", queueName);
87 89 return new TbRuleEngineProcessingDecision(true, null);
88 90 } else {
89 91 ConcurrentMap<UUID, TbProtoQueueMsg<TransportProtos.ToRuleEngineMsg>> toReprocess = new ConcurrentHashMap<>(initialTotalCount);
... ... @@ -96,8 +98,7 @@ public class TbRuleEngineProcessingStrategyFactory {
96 98 if (retrySuccessful) {
97 99 result.getSuccessMap().forEach(toReprocess::put);
98 100 }
99   - log.info("Going to reprocess {} messages", toReprocess.size());
100   - //TODO: 2.5 Log most popular rule nodes by error count;
  101 + log.info("[{}] Going to reprocess {} messages", queueName, toReprocess.size());
101 102 if (log.isTraceEnabled()) {
102 103 toReprocess.forEach((id, msg) -> log.trace("Going to reprocess [{}]: {}", id, msg.getValue()));
103 104 }
... ... @@ -116,9 +117,15 @@ public class TbRuleEngineProcessingStrategyFactory {
116 117
117 118 private static class SkipStrategy implements TbRuleEngineProcessingStrategy {
118 119
  120 + private final String queueName;
  121 +
  122 + public SkipStrategy(String name) {
  123 + this.queueName = name;
  124 + }
  125 +
119 126 @Override
120 127 public TbRuleEngineProcessingDecision analyze(TbRuleEngineProcessingResult result) {
121   - log.info("Skip reprocess of the rule engine pack");
  128 + log.info("[{}] Reprocessing skipped for {} failed and {} timeout messages", queueName, result.getFailureMap().size(), result.getPendingMap().size());
122 129 return new TbRuleEngineProcessingDecision(true, null);
123 130 }
124 131 }
... ...
... ... @@ -19,7 +19,6 @@ import lombok.Getter;
19 19 import lombok.RequiredArgsConstructor;
20 20 import lombok.ToString;
21 21 import org.thingsboard.rule.engine.api.RpcError;
22   -import org.thingsboard.server.common.msg.cluster.ServerAddress;
23 22
24 23 import java.util.Optional;
25 24 import java.util.UUID;
... ...
... ... @@ -22,11 +22,8 @@ import org.thingsboard.rule.engine.api.msg.ToDeviceActorNotificationMsg;
22 22 import org.thingsboard.server.common.data.id.DeviceId;
23 23 import org.thingsboard.server.common.data.id.TenantId;
24 24 import org.thingsboard.server.common.msg.MsgType;
25   -import org.thingsboard.server.common.msg.cluster.ServerAddress;
26 25 import org.thingsboard.server.common.msg.rpc.ToDeviceRpcRequest;
27 26
28   -import java.util.Optional;
29   -
30 27 /**
31 28 * Created by ashvayka on 16.04.18.
32 29 */
... ...
... ... @@ -55,7 +55,7 @@ import org.thingsboard.server.queue.discovery.PartitionService;
55 55 import org.thingsboard.server.common.msg.queue.ServiceType;
56 56 import org.thingsboard.server.common.msg.queue.TopicPartitionInfo;
57 57 import org.thingsboard.server.gen.transport.TransportProtos;
58   -import org.thingsboard.server.common.msg.queue.TbMsgCallback;
  58 +import org.thingsboard.server.common.msg.queue.TbCallback;
59 59 import org.thingsboard.server.queue.provider.TbQueueProducerProvider;
60 60 import org.thingsboard.server.queue.util.TbCoreComponent;
61 61 import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService;
... ... @@ -242,7 +242,7 @@ public class DefaultDeviceStateService implements DeviceStateService {
242 242 }
243 243
244 244 @Override
245   - public void onQueueMsg(TransportProtos.DeviceStateServiceMsgProto proto, TbMsgCallback callback) {
  245 + public void onQueueMsg(TransportProtos.DeviceStateServiceMsgProto proto, TbCallback callback) {
246 246 try {
247 247 TenantId tenantId = new TenantId(new UUID(proto.getTenantIdMSB(), proto.getTenantIdLSB()));
248 248 DeviceId deviceId = new DeviceId(new UUID(proto.getDeviceIdMSB(), proto.getDeviceIdLSB()));
... ...
... ... @@ -20,7 +20,7 @@ import org.thingsboard.server.common.data.Device;
20 20 import org.thingsboard.server.common.data.id.DeviceId;
21 21 import org.thingsboard.server.queue.discovery.PartitionChangeEvent;
22 22 import org.thingsboard.server.gen.transport.TransportProtos;
23   -import org.thingsboard.server.common.msg.queue.TbMsgCallback;
  23 +import org.thingsboard.server.common.msg.queue.TbCallback;
24 24
25 25 /**
26 26 * Created by ashvayka on 01.05.18.
... ... @@ -41,6 +41,6 @@ public interface DeviceStateService extends ApplicationListener<PartitionChangeE
41 41
42 42 void onDeviceInactivityTimeoutUpdate(DeviceId deviceId, long inactivityTimeout);
43 43
44   - void onQueueMsg(TransportProtos.DeviceStateServiceMsgProto serverAddress, TbMsgCallback bytes);
  44 + void onQueueMsg(TransportProtos.DeviceStateServiceMsgProto serverAddress, TbCallback bytes);
45 45
46 46 }
... ...
  1 +/**
  2 + * Copyright © 2016-2020 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.service.stats;
  17 +
  18 +import com.google.common.util.concurrent.FutureCallback;
  19 +import lombok.Data;
  20 +import lombok.extern.slf4j.Slf4j;
  21 +import org.springframework.stereotype.Service;
  22 +import org.thingsboard.server.common.data.asset.Asset;
  23 +import org.thingsboard.server.common.data.id.AssetId;
  24 +import org.thingsboard.server.common.data.id.TenantId;
  25 +import org.thingsboard.server.common.data.kv.BasicTsKvEntry;
  26 +import org.thingsboard.server.common.data.kv.JsonDataEntry;
  27 +import org.thingsboard.server.common.data.kv.LongDataEntry;
  28 +import org.thingsboard.server.common.data.kv.TsKvEntry;
  29 +import org.thingsboard.server.dao.asset.AssetService;
  30 +import org.thingsboard.server.queue.discovery.TbServiceInfoProvider;
  31 +import org.thingsboard.server.queue.util.TbRuleEngineComponent;
  32 +import org.thingsboard.server.service.queue.TbRuleEngineConsumerStats;
  33 +import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService;
  34 +
  35 +import javax.annotation.Nullable;
  36 +import java.util.Collections;
  37 +import java.util.List;
  38 +import java.util.concurrent.ConcurrentHashMap;
  39 +import java.util.concurrent.ConcurrentMap;
  40 +import java.util.concurrent.locks.Lock;
  41 +import java.util.concurrent.locks.ReentrantLock;
  42 +import java.util.stream.Collectors;
  43 +
  44 +@TbRuleEngineComponent
  45 +@Service
  46 +@Slf4j
  47 +public class DefaultRuleEngineStatisticsService implements RuleEngineStatisticsService {
  48 +
  49 + public static final FutureCallback<Void> CALLBACK = new FutureCallback<Void>() {
  50 + @Override
  51 + public void onSuccess(@Nullable Void result) {
  52 +
  53 + }
  54 +
  55 + @Override
  56 + public void onFailure(Throwable t) {
  57 + log.warn("Failed to persist statistics", t);
  58 + }
  59 + };
  60 +
  61 + private final TbServiceInfoProvider serviceInfoProvider;
  62 + private final TelemetrySubscriptionService tsService;
  63 + private final Lock lock = new ReentrantLock();
  64 + private final AssetService assetService;
  65 + private final ConcurrentMap<TenantQueueKey, AssetId> tenantQueueAssets;
  66 +
  67 + public DefaultRuleEngineStatisticsService(TelemetrySubscriptionService tsService, TbServiceInfoProvider serviceInfoProvider, AssetService assetService) {
  68 + this.tsService = tsService;
  69 + this.serviceInfoProvider = serviceInfoProvider;
  70 + this.assetService = assetService;
  71 + this.tenantQueueAssets = new ConcurrentHashMap<>();
  72 + }
  73 +
  74 + @Override
  75 + public void reportQueueStats(long ts, TbRuleEngineConsumerStats ruleEngineStats) {
  76 + String queueName = ruleEngineStats.getQueueName();
  77 + ruleEngineStats.getTenantStats().forEach((id, stats) -> {
  78 + TenantId tenantId = new TenantId(id);
  79 + AssetId serviceAssetId = getServiceAssetId(tenantId, queueName);
  80 + if (stats.getTotalMsgCounter().get() > 0) {
  81 + List<TsKvEntry> tsList = stats.getCounters().entrySet().stream()
  82 + .map(kv -> new BasicTsKvEntry(ts, new LongDataEntry(kv.getKey(), (long) kv.getValue().get())))
  83 + .collect(Collectors.toList());
  84 + if (!tsList.isEmpty()) {
  85 + tsService.saveAndNotify(tenantId, serviceAssetId, tsList, CALLBACK);
  86 + }
  87 + }
  88 + });
  89 + ruleEngineStats.getTenantExceptions().forEach((tenantId, e) -> {
  90 + TsKvEntry tsKv = new BasicTsKvEntry(ts, new JsonDataEntry("ruleEngineException", e.toJsonString()));
  91 + tsService.saveAndNotify(tenantId, getServiceAssetId(tenantId, queueName), Collections.singletonList(tsKv), CALLBACK);
  92 + });
  93 + ruleEngineStats.reset();
  94 + }
  95 +
  96 + private AssetId getServiceAssetId(TenantId tenantId, String queueName) {
  97 + TenantQueueKey key = new TenantQueueKey(tenantId, queueName);
  98 + AssetId assetId = tenantQueueAssets.get(key);
  99 + if (assetId == null) {
  100 + lock.lock();
  101 + try {
  102 + assetId = tenantQueueAssets.get(key);
  103 + if (assetId == null) {
  104 + Asset asset = assetService.findAssetByTenantIdAndName(tenantId, queueName + "_" + serviceInfoProvider.getServiceId());
  105 + if (asset == null) {
  106 + asset = new Asset();
  107 + asset.setTenantId(tenantId);
  108 + asset.setName(queueName + "_" + serviceInfoProvider.getServiceId());
  109 + asset.setType("TbServiceQueue");
  110 + asset = assetService.saveAsset(asset);
  111 + }
  112 + assetId = asset.getId();
  113 + tenantQueueAssets.put(key, assetId);
  114 + }
  115 + } finally {
  116 + lock.unlock();
  117 + }
  118 + }
  119 + return assetId;
  120 + }
  121 +
  122 + @Data
  123 + private static class TenantQueueKey {
  124 + private final TenantId tenantId;
  125 + private final String queueName;
  126 + }
  127 +}
... ...
application/src/main/java/org/thingsboard/server/service/stats/RuleEngineStatisticsService.java renamed from common/message/src/main/java/org/thingsboard/server/common/msg/cluster/ServerType.java
... ... @@ -13,11 +13,11 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.common.msg.cluster;
  16 +package org.thingsboard.server.service.stats;
17 17
18   -/**
19   - * Created by ashvayka on 23.09.18.
20   - */
21   -public enum ServerType {
22   - CORE
  18 +import org.thingsboard.server.service.queue.TbRuleEngineConsumerStats;
  19 +
  20 +public interface RuleEngineStatisticsService {
  21 +
  22 + void reportQueueStats(long ts, TbRuleEngineConsumerStats stats);
23 23 }
... ...
... ... @@ -34,7 +34,7 @@ import org.thingsboard.server.common.data.kv.BasicTsKvEntry;
34 34 import org.thingsboard.server.common.data.kv.ReadTsKvQuery;
35 35 import org.thingsboard.server.common.data.kv.TsKvEntry;
36 36 import org.thingsboard.server.common.msg.queue.ServiceType;
37   -import org.thingsboard.server.common.msg.queue.TbMsgCallback;
  37 +import org.thingsboard.server.common.msg.queue.TbCallback;
38 38 import org.thingsboard.server.common.msg.queue.TopicPartitionInfo;
39 39 import org.thingsboard.server.dao.attributes.AttributesService;
40 40 import org.thingsboard.server.dao.timeseries.TimeseriesService;
... ... @@ -123,7 +123,7 @@ public class DefaultSubscriptionManagerService implements SubscriptionManagerSer
123 123 }
124 124
125 125 @Override
126   - public void addSubscription(TbSubscription subscription, TbMsgCallback callback) {
  126 + public void addSubscription(TbSubscription subscription, TbCallback callback) {
127 127 log.trace("[{}][{}][{}] Registering remote subscription for entity [{}]",
128 128 subscription.getServiceId(), subscription.getSessionId(), subscription.getSubscriptionId(), subscription.getEntityId());
129 129 TopicPartitionInfo tpi = partitionService.resolve(ServiceType.TB_CORE, subscription.getTenantId(), subscription.getEntityId());
... ... @@ -151,7 +151,7 @@ public class DefaultSubscriptionManagerService implements SubscriptionManagerSer
151 151 }
152 152
153 153 @Override
154   - public void cancelSubscription(String sessionId, int subscriptionId, TbMsgCallback callback) {
  154 + public void cancelSubscription(String sessionId, int subscriptionId, TbCallback callback) {
155 155 log.debug("[{}][{}] Going to remove subscription.", sessionId, subscriptionId);
156 156 Map<Integer, TbSubscription> sessionSubscriptions = subscriptionsByWsSessionId.get(sessionId);
157 157 if (sessionSubscriptions != null) {
... ... @@ -189,7 +189,7 @@ public class DefaultSubscriptionManagerService implements SubscriptionManagerSer
189 189 }
190 190
191 191 @Override
192   - public void onTimeSeriesUpdate(TenantId tenantId, EntityId entityId, List<TsKvEntry> ts, TbMsgCallback callback) {
  192 + public void onTimeSeriesUpdate(TenantId tenantId, EntityId entityId, List<TsKvEntry> ts, TbCallback callback) {
193 193 onLocalSubUpdate(entityId,
194 194 s -> {
195 195 if (TbSubscriptionType.TIMESERIES.equals(s.getType())) {
... ... @@ -213,7 +213,7 @@ public class DefaultSubscriptionManagerService implements SubscriptionManagerSer
213 213 }
214 214
215 215 @Override
216   - public void onAttributesUpdate(TenantId tenantId, EntityId entityId, String scope, List<AttributeKvEntry> attributes, TbMsgCallback callback) {
  216 + public void onAttributesUpdate(TenantId tenantId, EntityId entityId, String scope, List<AttributeKvEntry> attributes, TbCallback callback) {
217 217 onLocalSubUpdate(entityId,
218 218 s -> {
219 219 if (TbSubscriptionType.ATTRIBUTES.equals(s.getType())) {
... ... @@ -261,7 +261,7 @@ public class DefaultSubscriptionManagerService implements SubscriptionManagerSer
261 261 if (subscriptionUpdate != null && !subscriptionUpdate.isEmpty()) {
262 262 if (serviceId.equals(s.getServiceId())) {
263 263 SubscriptionUpdate update = new SubscriptionUpdate(s.getSubscriptionId(), subscriptionUpdate);
264   - localSubscriptionService.onSubscriptionUpdate(s.getSessionId(), update, TbMsgCallback.EMPTY);
  264 + localSubscriptionService.onSubscriptionUpdate(s.getSessionId(), update, TbCallback.EMPTY);
265 265 } else {
266 266 TopicPartitionInfo tpi = partitionService.getNotificationsTopic(ServiceType.TB_CORE, s.getServiceId());
267 267 toCoreNotificationsProducer.send(tpi, toProto(s, subscriptionUpdate), null);
... ...
... ... @@ -35,7 +35,7 @@ import org.thingsboard.server.queue.discovery.PartitionChangeEvent;
35 35 import org.thingsboard.server.queue.discovery.PartitionService;
36 36 import org.thingsboard.server.common.msg.queue.ServiceType;
37 37 import org.thingsboard.server.common.msg.queue.TopicPartitionInfo;
38   -import org.thingsboard.server.common.msg.queue.TbMsgCallback;
  38 +import org.thingsboard.server.common.msg.queue.TbCallback;
39 39 import org.thingsboard.server.queue.provider.TbQueueProducerProvider;
40 40 import org.thingsboard.server.queue.util.TbCoreComponent;
41 41 import org.thingsboard.server.service.telemetry.TelemetryWebSocketService;
... ... @@ -135,7 +135,7 @@ public class DefaultTbLocalSubscriptionService implements TbLocalSubscriptionSer
135 135 if (currentPartitions.contains(tpi)) {
136 136 // Subscription is managed on the same server;
137 137 if (pushToLocalService) {
138   - subscriptionManagerService.addSubscription(subscription, TbMsgCallback.EMPTY);
  138 + subscriptionManagerService.addSubscription(subscription, TbCallback.EMPTY);
139 139 }
140 140 } else {
141 141 // Push to the queue;
... ... @@ -145,7 +145,7 @@ public class DefaultTbLocalSubscriptionService implements TbLocalSubscriptionSer
145 145 }
146 146
147 147 @Override
148   - public void onSubscriptionUpdate(String sessionId, SubscriptionUpdate update, TbMsgCallback callback) {
  148 + public void onSubscriptionUpdate(String sessionId, SubscriptionUpdate update, TbCallback callback) {
149 149 TbSubscription subscription = subscriptionsBySessionId
150 150 .getOrDefault(sessionId, Collections.emptyMap()).get(update.getSubscriptionId());
151 151 if (subscription != null) {
... ... @@ -177,7 +177,7 @@ public class DefaultTbLocalSubscriptionService implements TbLocalSubscriptionSer
177 177 TopicPartitionInfo tpi = partitionService.resolve(ServiceType.TB_CORE, subscription.getTenantId(), subscription.getEntityId());
178 178 if (currentPartitions.contains(tpi)) {
179 179 // Subscription is managed on the same server;
180   - subscriptionManagerService.cancelSubscription(sessionId, subscriptionId, TbMsgCallback.EMPTY);
  180 + subscriptionManagerService.cancelSubscription(sessionId, subscriptionId, TbCallback.EMPTY);
181 181 } else {
182 182 // Push to the queue;
183 183 TransportProtos.ToCoreMsg toCoreMsg = TbSubscriptionUtils.toCloseSubscriptionProto(subscription);
... ...
... ... @@ -21,18 +21,18 @@ import org.thingsboard.server.common.data.id.TenantId;
21 21 import org.thingsboard.server.common.data.kv.AttributeKvEntry;
22 22 import org.thingsboard.server.common.data.kv.TsKvEntry;
23 23 import org.thingsboard.server.queue.discovery.PartitionChangeEvent;
24   -import org.thingsboard.server.common.msg.queue.TbMsgCallback;
  24 +import org.thingsboard.server.common.msg.queue.TbCallback;
25 25
26 26 import java.util.List;
27 27
28 28 public interface SubscriptionManagerService extends ApplicationListener<PartitionChangeEvent> {
29 29
30   - void addSubscription(TbSubscription subscription, TbMsgCallback callback);
  30 + void addSubscription(TbSubscription subscription, TbCallback callback);
31 31
32   - void cancelSubscription(String sessionId, int subscriptionId, TbMsgCallback callback);
  32 + void cancelSubscription(String sessionId, int subscriptionId, TbCallback callback);
33 33
34   - void onTimeSeriesUpdate(TenantId tenantId, EntityId entityId, List<TsKvEntry> ts, TbMsgCallback callback);
  34 + void onTimeSeriesUpdate(TenantId tenantId, EntityId entityId, List<TsKvEntry> ts, TbCallback callback);
35 35
36   - void onAttributesUpdate(TenantId tenantId, EntityId entityId, String scope, List<AttributeKvEntry> attributes, TbMsgCallback callback);
  36 + void onAttributesUpdate(TenantId tenantId, EntityId entityId, String scope, List<AttributeKvEntry> attributes, TbCallback callback);
37 37
38 38 }
... ...
... ... @@ -17,7 +17,7 @@ package org.thingsboard.server.service.subscription;
17 17
18 18 import org.thingsboard.server.queue.discovery.ClusterTopologyChangeEvent;
19 19 import org.thingsboard.server.queue.discovery.PartitionChangeEvent;
20   -import org.thingsboard.server.common.msg.queue.TbMsgCallback;
  20 +import org.thingsboard.server.common.msg.queue.TbCallback;
21 21 import org.thingsboard.server.service.telemetry.sub.SubscriptionUpdate;
22 22
23 23 public interface TbLocalSubscriptionService {
... ... @@ -28,7 +28,7 @@ public interface TbLocalSubscriptionService {
28 28
29 29 void cancelAllSessionSubscriptions(String sessionId);
30 30
31   - void onSubscriptionUpdate(String sessionId, SubscriptionUpdate update, TbMsgCallback callback);
  31 + void onSubscriptionUpdate(String sessionId, SubscriptionUpdate update, TbCallback callback);
32 32
33 33 void onApplicationEvent(PartitionChangeEvent event);
34 34
... ...
... ... @@ -41,7 +41,7 @@ import org.thingsboard.server.queue.discovery.PartitionChangeEvent;
41 41 import org.thingsboard.server.queue.discovery.PartitionService;
42 42 import org.thingsboard.server.common.msg.queue.ServiceType;
43 43 import org.thingsboard.server.common.msg.queue.TopicPartitionInfo;
44   -import org.thingsboard.server.common.msg.queue.TbMsgCallback;
  44 +import org.thingsboard.server.common.msg.queue.TbCallback;
45 45 import org.thingsboard.server.queue.provider.TbQueueProducerProvider;
46 46 import org.thingsboard.server.service.subscription.SubscriptionManagerService;
47 47 import org.thingsboard.server.service.subscription.TbSubscriptionUtils;
... ... @@ -166,7 +166,7 @@ public class DefaultTelemetrySubscriptionService implements TelemetrySubscriptio
166 166 TopicPartitionInfo tpi = partitionService.resolve(ServiceType.TB_CORE, tenantId, entityId);
167 167 if (currentPartitions.contains(tpi)) {
168 168 if (subscriptionManagerService.isPresent()) {
169   - subscriptionManagerService.get().onAttributesUpdate(tenantId, entityId, scope, attributes, TbMsgCallback.EMPTY);
  169 + subscriptionManagerService.get().onAttributesUpdate(tenantId, entityId, scope, attributes, TbCallback.EMPTY);
170 170 } else {
171 171 log.warn("Possible misconfiguration because subscriptionManagerService is null!");
172 172 }
... ... @@ -180,7 +180,7 @@ public class DefaultTelemetrySubscriptionService implements TelemetrySubscriptio
180 180 TopicPartitionInfo tpi = partitionService.resolve(ServiceType.TB_CORE, tenantId, entityId);
181 181 if (currentPartitions.contains(tpi)) {
182 182 if (subscriptionManagerService.isPresent()) {
183   - subscriptionManagerService.get().onTimeSeriesUpdate(tenantId, entityId, ts, TbMsgCallback.EMPTY);
  183 + subscriptionManagerService.get().onTimeSeriesUpdate(tenantId, entityId, ts, TbCallback.EMPTY);
184 184 } else {
185 185 log.warn("Possible misconfiguration because subscriptionManagerService is null!");
186 186 }
... ...
... ... @@ -17,11 +17,7 @@ package org.thingsboard.server.service.telemetry;
17 17
18 18 import org.springframework.context.ApplicationListener;
19 19 import org.thingsboard.rule.engine.api.RuleEngineTelemetryService;
20   -import org.thingsboard.server.common.data.id.EntityId;
21   -import org.thingsboard.server.common.data.id.TenantId;
22   -import org.thingsboard.server.common.msg.cluster.ServerAddress;
23 20 import org.thingsboard.server.queue.discovery.PartitionChangeEvent;
24   -import org.thingsboard.server.service.telemetry.sub.SubscriptionState;
25 21
26 22 /**
27 23 * Created by ashvayka on 27.03.18.
... ...
1   -/**
2   - * Copyright © 2016-2020 The Thingsboard Authors
3   - *
4   - * Licensed under the Apache License, Version 2.0 (the "License");
5   - * you may not use this file except in compliance with the License.
6   - * You may obtain a copy of the License at
7   - *
8   - * http://www.apache.org/licenses/LICENSE-2.0
9   - *
10   - * Unless required by applicable law or agreed to in writing, software
11   - * distributed under the License is distributed on an "AS IS" BASIS,
12   - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   - * See the License for the specific language governing permissions and
14   - * limitations under the License.
15   - */
16   -package org.thingsboard.server.service.telemetry.sub;
17   -
18   -import lombok.AllArgsConstructor;
19   -import lombok.Data;
20   -import org.thingsboard.server.common.data.id.EntityId;
21   -import org.thingsboard.server.common.msg.cluster.ServerAddress;
22   -import org.thingsboard.server.service.telemetry.TelemetryFeature;
23   -
24   -import java.util.Map;
25   -
26   -@Data
27   -@AllArgsConstructor
28   -public class Subscription {
29   -
30   - private final SubscriptionState sub;
31   - private final boolean local;
32   - private ServerAddress server;
33   - private long startTime;
34   - private long endTime;
35   -
36   - public Subscription(SubscriptionState sub, boolean local, ServerAddress server) {
37   - this(sub, local, server, 0L, 0L);
38   - }
39   -
40   - public String getWsSessionId() {
41   - return getSub().getWsSessionId();
42   - }
43   -
44   - public int getSubscriptionId() {
45   - return getSub().getSubscriptionId();
46   - }
47   -
48   - public EntityId getEntityId() {
49   - return getSub().getEntityId();
50   - }
51   -
52   - public TelemetryFeature getType() {
53   - return getSub().getType();
54   - }
55   -
56   - public String getScope() {
57   - return getSub().getScope();
58   - }
59   -
60   - public boolean isAllKeys() {
61   - return getSub().isAllKeys();
62   - }
63   -
64   - public Map<String, Long> getKeyStates() {
65   - return getSub().getKeyStates();
66   - }
67   -
68   - public void setKeyState(String key, long ts) {
69   - getSub().getKeyStates().put(key, ts);
70   - }
71   -
72   - @Override
73   - public String toString() {
74   - return "Subscription{" +
75   - "sub=" + sub +
76   - ", local=" + local +
77   - ", server=" + server +
78   - '}';
79   - }
80   -}
... ... @@ -22,7 +22,6 @@ import org.thingsboard.common.util.ThingsBoardThreadFactory;
22 22 import org.thingsboard.rule.engine.api.RuleChainTransactionService;
23 23 import org.thingsboard.server.common.data.id.EntityId;
24 24 import org.thingsboard.server.common.msg.TbMsg;
25   -import org.thingsboard.server.common.msg.cluster.ServerAddress;
26 25 import org.thingsboard.server.queue.util.TbRuleEngineComponent;
27 26 import org.thingsboard.server.service.executors.DbCallbackExecutorService;
28 27
... ... @@ -114,13 +113,6 @@ public class BaseRuleChainTransactionService implements RuleChainTransactionServ
114 113 // }
115 114 }
116 115
117   - @Override
118   - public void onRemoteTransactionMsg(ServerAddress serverAddress, byte[] data) {
119   - endLocalTransaction(TbMsg.fromBytes(data, null), msg -> {
120   - }, error -> {
121   - });
122   - }
123   -
124 116 private void addMsgToQueues(BlockingQueue<TbTransactionTask> queue, TbTransactionTask transactionTask) {
125 117 queue.offer(transactionTask);
126 118 timeoutQueue.offer(transactionTask);
... ... @@ -230,9 +222,4 @@ public class BaseRuleChainTransactionService implements RuleChainTransactionServ
230 222 callbackExecutor.executeAsync(task);
231 223 }
232 224
233   - private void sendTransactionEventToRemoteServer(TbMsg msg, ServerAddress address) {
234   - log.trace("[{}][{}] Originator is monitored on other server: {}", msg.getTransactionData().getOriginatorId(), msg.getTransactionData().getTransactionId(), address);
235   - //TODO 2.5
236   -// clusterRpcService.tell(address, ClusterAPIProtos.MessageType.CLUSTER_TRANSACTION_SERVICE_MESSAGE, TbMsg.toByteArray(msg));
237   - }
238 225 }
... ...
... ... @@ -23,7 +23,7 @@ import org.thingsboard.server.common.msg.TbActorMsg;
23 23 import org.thingsboard.server.common.msg.aware.DeviceAwareMsg;
24 24 import org.thingsboard.server.common.msg.aware.TenantAwareMsg;
25 25 import org.thingsboard.server.gen.transport.TransportProtos.TransportToDeviceActorMsg;
26   -import org.thingsboard.server.common.msg.queue.TbMsgCallback;
  26 +import org.thingsboard.server.common.msg.queue.TbCallback;
27 27
28 28 import java.io.Serializable;
29 29 import java.util.UUID;
... ... @@ -37,9 +37,9 @@ public class TransportToDeviceActorMsgWrapper implements TbActorMsg, DeviceAware
37 37 private final TenantId tenantId;
38 38 private final DeviceId deviceId;
39 39 private final TransportToDeviceActorMsg msg;
40   - private final TbMsgCallback callback;
  40 + private final TbCallback callback;
41 41
42   - public TransportToDeviceActorMsgWrapper(TransportToDeviceActorMsg msg, TbMsgCallback callback) {
  42 + public TransportToDeviceActorMsgWrapper(TransportToDeviceActorMsg msg, TbCallback callback) {
43 43 this.msg = msg;
44 44 this.callback = callback;
45 45 this.tenantId = new TenantId(new UUID(msg.getSessionInfo().getTenantIdMSB(), msg.getSessionInfo().getTenantIdLSB()));
... ...
... ... @@ -27,8 +27,8 @@
27 27
28 28 <logger name="org.thingsboard.server" level="INFO" />
29 29 <logger name="akka" level="INFO" />
30   - <logger name="org.thingsboard.server.service.queue" level="TRACE" />
31   - <logger name="org.thingsboard.server.service.transport" level="TRACE" />
  30 +<!-- <logger name="org.thingsboard.server.service.queue" level="TRACE" />-->
  31 +<!-- <logger name="org.thingsboard.server.service.transport" level="TRACE" />-->
32 32
33 33 <root level="INFO">
34 34 <appender-ref ref="STDOUT"/>
... ...
... ... @@ -561,7 +561,7 @@ queue:
561 561 poll-interval: "${TB_QUEUE_RULE_ENGINE_POLL_INTERVAL_MS:25}"
562 562 pack-processing-timeout: "${TB_QUEUE_RULE_ENGINE_PACK_PROCESSING_TIMEOUT_MS:60000}"
563 563 stats:
564   - enabled: "${TB_QUEUE_RULE_ENGINE_STATS_ENABLED:false}"
  564 + enabled: "${TB_QUEUE_RULE_ENGINE_STATS_ENABLED:true}"
565 565 print-interval-ms: "${TB_QUEUE_RULE_ENGINE_STATS_PRINT_INTERVAL_MS:10000}"
566 566 queues: # TODO 2.5: specify correct ENV variable names.
567 567 -
... ... @@ -577,7 +577,7 @@ queue:
577 577 failure-percentage: "${TB_QUEUE_RULE_ENGINE_STRATEGY_FAILURE_PERCENTAGE:0}" # Skip retry if failures or timeouts are less then X percentage of messages;
578 578 pause-between-retries: "${TB_QUEUE_RULE_ENGINE_STRATEGY_RETRY_PAUSE:3}"# Time in seconds to wait in consumer thread before retries;
579 579 -
580   - name: "HighPriority"
  580 + name: "${TB_QUEUE_RULE_ENGINE_HP_QUEUE_NAME:HighPriority}"
581 581 topic: "${TB_QUEUE_RULE_ENGINE_TOPIC:tb.rule-engine.hp}"
582 582 poll-interval: "${TB_QUEUE_RULE_ENGINE_POLL_INTERVAL_MS:25}"
583 583 partitions: "${TB_QUEUE_RULE_ENGINE_PARTITIONS:3}"
... ... @@ -594,7 +594,7 @@ queue:
594 594 poll_interval: "${TB_QUEUE_CORE_POLL_INTERVAL_MS:25}"
595 595
596 596 service:
597   - type: "${TB_SERVICE_TYPE:monolith}" # monolith or tb-core or tb-rule-engine or tb-transport
  597 + type: "${TB_SERVICE_TYPE:monolith}" # monolith or tb-core or tb-rule-engine
598 598 # Unique id for this service (autogenerated if empty)
599 599 id: "${TB_SERVICE_ID:}"
600 600 tenant_id: "${TB_SERVICE_TENANT_ID:}" # empty or specific tenant id.
... ...
... ... @@ -35,8 +35,6 @@ import org.thingsboard.server.common.data.security.Authority;
35 35 import org.thingsboard.server.common.msg.TbMsg;
36 36 import org.thingsboard.server.common.msg.TbMsgDataType;
37 37 import org.thingsboard.server.common.msg.TbMsgMetaData;
38   -import org.thingsboard.server.common.msg.cluster.SendToClusterMsg;
39   -import org.thingsboard.server.common.msg.queue.QueueToRuleEngineMsg;
40 38 import org.thingsboard.server.controller.AbstractRuleEngineControllerTest;
41 39 import org.thingsboard.server.dao.attributes.AttributesService;
42 40
... ...
... ... @@ -39,8 +39,6 @@ import org.thingsboard.server.common.data.security.Authority;
39 39 import org.thingsboard.server.common.msg.TbMsg;
40 40 import org.thingsboard.server.common.msg.TbMsgDataType;
41 41 import org.thingsboard.server.common.msg.TbMsgMetaData;
42   -import org.thingsboard.server.common.msg.cluster.SendToClusterMsg;
43   -import org.thingsboard.server.common.msg.queue.QueueToRuleEngineMsg;
44 42 import org.thingsboard.server.controller.AbstractRuleEngineControllerTest;
45 43 import org.thingsboard.server.dao.attributes.AttributesService;
46 44
... ...
... ... @@ -34,11 +34,6 @@ public enum MsgType {
34 34 APP_INIT_MSG,
35 35
36 36 /**
37   - * All messages, could be send to cluster
38   - */
39   - SEND_TO_CLUSTER_MSG,
40   -
41   - /**
42 37 * ADDED/UPDATED/DELETED events for main entities.
43 38 *
44 39 * See {@link org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg}
... ...
... ... @@ -5,7 +5,7 @@
5 5 * you may not use this file except in compliance with the License.
6 6 * You may obtain a copy of the License at
7 7 *
8   - * http://www.apache.org/licenses/LICENSE-2.0
  8 + * http://www.apache.org/licenses/LICENSE-2.0
9 9 *
10 10 * Unless required by applicable law or agreed to in writing, software
11 11 * distributed under the License is distributed on an "AS IS" BASIS,
... ... @@ -17,7 +17,6 @@ package org.thingsboard.server.common.msg;
17 17
18 18 import com.google.protobuf.ByteString;
19 19 import com.google.protobuf.InvalidProtocolBufferException;
20   -import lombok.AllArgsConstructor;
21 20 import lombok.Builder;
22 21 import lombok.Data;
23 22 import lombok.extern.slf4j.Slf4j;
... ... @@ -29,7 +28,6 @@ import org.thingsboard.server.common.msg.gen.MsgProtos;
29 28 import org.thingsboard.server.common.msg.queue.TbMsgCallback;
30 29
31 30 import java.io.Serializable;
32   -import java.nio.ByteBuffer;
33 31 import java.util.UUID;
34 32
35 33 /**
... ...
... ... @@ -33,6 +33,7 @@ public final class QueueToRuleEngineMsg implements TbActorMsg {
33 33 private final TenantId tenantId;
34 34 private final TbMsg tbMsg;
35 35 private final Set<String> relationTypes;
  36 + private final String failureMessage;
36 37
37 38 @Override
38 39 public MsgType getMsgType() {
... ...
common/message/src/main/java/org/thingsboard/server/common/msg/queue/RuleEngineException.java renamed from common/message/src/main/java/org/thingsboard/server/common/msg/cluster/ServerAddress.java
... ... @@ -13,35 +13,26 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.common.msg.cluster;
  16 +package org.thingsboard.server.common.msg.queue;
17 17
18   -import lombok.Data;
19   -import lombok.EqualsAndHashCode;
  18 +import com.fasterxml.jackson.core.JsonProcessingException;
  19 +import com.fasterxml.jackson.databind.ObjectMapper;
  20 +import lombok.extern.slf4j.Slf4j;
20 21
21   -import java.io.Serializable;
  22 +@Slf4j
  23 +public class RuleEngineException extends Exception {
  24 + protected static final ObjectMapper mapper = new ObjectMapper();
22 25
23   -/**
24   - * @author Andrew Shvayka
25   - */
26   -@Data
27   -@EqualsAndHashCode
28   -public class ServerAddress implements Comparable<ServerAddress>, Serializable {
29   -
30   - private final String host;
31   - private final int port;
32   - private final ServerType serverType;
33   -
34   - @Override
35   - public int compareTo(ServerAddress o) {
36   - int result = this.host.compareTo(o.host);
37   - if (result == 0) {
38   - result = this.port - o.port;
39   - }
40   - return result;
  26 + public RuleEngineException(String message) {
  27 + super(message != null ? message : "Unknown");
41 28 }
42 29
43   - @Override
44   - public String toString() {
45   - return '[' + host + ':' + port + ']';
  30 + public String toJsonString() {
  31 + try {
  32 + return mapper.writeValueAsString(mapper.createObjectNode().put("message", getMessage()));
  33 + } catch (JsonProcessingException e) {
  34 + log.warn("Failed to serialize exception ", e);
  35 + throw new RuntimeException(e);
  36 + }
46 37 }
47 38 }
... ...
  1 +/**
  2 + * Copyright © 2016-2020 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.common.msg.queue;
  17 +
  18 +import com.fasterxml.jackson.core.JsonProcessingException;
  19 +import lombok.Getter;
  20 +import lombok.extern.slf4j.Slf4j;
  21 +import org.thingsboard.server.common.data.id.RuleChainId;
  22 +import org.thingsboard.server.common.data.id.RuleNodeId;
  23 +import org.thingsboard.server.common.data.rule.RuleNode;
  24 +
  25 +@Slf4j
  26 +public class RuleNodeException extends RuleEngineException {
  27 + @Getter
  28 + private final String ruleChainName;
  29 + @Getter
  30 + private final String ruleNodeName;
  31 + @Getter
  32 + private final RuleChainId ruleChainId;
  33 + @Getter
  34 + private final RuleNodeId ruleNodeId;
  35 +
  36 + public RuleNodeException(String message, String ruleChainName, RuleNode ruleNode) {
  37 + super(message);
  38 + this.ruleChainName = ruleChainName;
  39 + this.ruleNodeName = ruleNode.getName();
  40 + this.ruleChainId = ruleNode.getRuleChainId();
  41 + this.ruleNodeId = ruleNode.getId();
  42 + }
  43 +
  44 + public String toJsonString() {
  45 + try {
  46 + return mapper.writeValueAsString(mapper.createObjectNode()
  47 + .put("ruleNodeId", ruleNodeId.toString())
  48 + .put("ruleChainId", ruleChainId.toString())
  49 + .put("ruleNodeName", ruleNodeName)
  50 + .put("ruleChainName", ruleChainName)
  51 + .put("message", getMessage()));
  52 + } catch (JsonProcessingException e) {
  53 + log.warn("Failed to serialize exception ", e);
  54 + throw new RuntimeException(e);
  55 + }
  56 + }
  57 +
  58 +}
... ...
common/message/src/main/java/org/thingsboard/server/common/msg/queue/TbCallback.java renamed from application/src/main/java/org/thingsboard/server/actors/shared/rulechain/SystemRuleChainManager.java
... ... @@ -13,36 +13,25 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.actors.shared.rulechain;
17   -
18   -import org.thingsboard.server.actors.ActorSystemContext;
19   -import org.thingsboard.server.actors.service.DefaultActorService;
20   -import org.thingsboard.server.common.data.id.TenantId;
21   -import org.thingsboard.server.common.data.page.PageDataIterable.FetchFunction;
22   -import org.thingsboard.server.common.data.page.TextPageData;
23   -import org.thingsboard.server.common.data.rule.RuleChain;
24   -import org.thingsboard.server.dao.model.ModelConstants;
25   -
26   -import java.util.Collections;
27   -
28   -public class SystemRuleChainManager extends RuleChainManager {
29   -
30   - public SystemRuleChainManager(ActorSystemContext systemContext) {
31   - super(systemContext);
32   - }
33   -
34   - @Override
35   - protected FetchFunction<RuleChain> getFetchEntitiesFunction() {
36   - return link -> new TextPageData<>(Collections.emptyList(), link);
37   - }
38   -
39   - @Override
40   - protected TenantId getTenantId() {
41   - return ModelConstants.SYSTEM_TENANT;
42   - }
43   -
44   - @Override
45   - protected String getDispatcherName() {
46   - return DefaultActorService.SYSTEM_RULE_DISPATCHER_NAME;
47   - }
  16 +package org.thingsboard.server.common.msg.queue;
  17 +
  18 +public interface TbCallback {
  19 +
  20 + TbCallback EMPTY = new TbCallback() {
  21 +
  22 + @Override
  23 + public void onSuccess() {
  24 +
  25 + }
  26 +
  27 + @Override
  28 + public void onFailure(Throwable t) {
  29 +
  30 + }
  31 + };
  32 +
  33 + void onSuccess();
  34 +
  35 + void onFailure(Throwable t);
  36 +
48 37 }
... ...
... ... @@ -25,13 +25,13 @@ public interface TbMsgCallback {
25 25 }
26 26
27 27 @Override
28   - public void onFailure(Throwable t) {
  28 + public void onFailure(RuleEngineException e) {
29 29
30 30 }
31 31 };
32 32
33 33 void onSuccess();
34 34
35   - void onFailure(Throwable t);
  35 + void onFailure(RuleEngineException e);
36 36
37 37 }
... ...
... ... @@ -15,6 +15,8 @@
15 15 */
16 16 package org.thingsboard.server.queue.common;
17 17
  18 +import org.thingsboard.server.common.msg.queue.RuleEngineException;
  19 +import org.thingsboard.server.common.msg.queue.TbCallback;
18 20 import org.thingsboard.server.common.msg.queue.TbMsgCallback;
19 21 import org.thingsboard.server.queue.TbQueueCallback;
20 22 import org.thingsboard.server.queue.TbQueueMsgMetadata;
... ... @@ -40,6 +42,6 @@ public class MultipleTbQueueTbMsgCallbackWrapper implements TbQueueCallback {
40 42
41 43 @Override
42 44 public void onFailure(Throwable t) {
43   - tbMsgCallback.onFailure(t);
  45 + tbMsgCallback.onFailure(new RuleEngineException(t.getMessage()));
44 46 }
45 47 }
... ...
... ... @@ -15,12 +15,12 @@
15 15 */
16 16 package org.thingsboard.server.queue.common;
17 17
  18 +import org.thingsboard.server.common.msg.queue.RuleEngineException;
  19 +import org.thingsboard.server.common.msg.queue.TbCallback;
18 20 import org.thingsboard.server.common.msg.queue.TbMsgCallback;
19 21 import org.thingsboard.server.queue.TbQueueCallback;
20 22 import org.thingsboard.server.queue.TbQueueMsgMetadata;
21 23
22   -import java.util.concurrent.atomic.AtomicInteger;
23   -
24 24 public class TbQueueTbMsgCallbackWrapper implements TbQueueCallback {
25 25
26 26 private final TbMsgCallback tbMsgCallback;
... ... @@ -36,6 +36,6 @@ public class TbQueueTbMsgCallbackWrapper implements TbQueueCallback {
36 36
37 37 @Override
38 38 public void onFailure(Throwable t) {
39   - tbMsgCallback.onFailure(t);
  39 + tbMsgCallback.onFailure(new RuleEngineException(t.getMessage()));
40 40 }
41 41 }
... ...
... ... @@ -86,24 +86,6 @@ public class ConsistentHashPartitionService implements PartitionService {
86 86 partitionTopics.put(new ServiceQueue(ServiceType.TB_CORE), coreTopic);
87 87 }
88 88
89   -// public Set<TopicPartitionInfo> getCurrentPartitions(ServiceType serviceType) {
90   -// ServiceInfo currentService = serviceInfoProvider.getServiceInfo();
91   -// TenantId tenantId = getSystemOrIsolatedTenantId(currentService);
92   -// ServiceQueueKey serviceQueueKey = new ServiceQueueKey(serviceType, tenantId);
93   -// List<Integer> partitions = myPartitions.get(serviceQueueKey);
94   -// Set<TopicPartitionInfo> topicPartitions = new LinkedHashSet<>();
95   -// for (Integer partition : partitions) {
96   -// TopicPartitionInfo.TopicPartitionInfoBuilder tpi = TopicPartitionInfo.builder();
97   -// tpi.topic(partitionTopics.get(serviceType));
98   -// tpi.partition(partition);
99   -// if (!tenantId.isNullUid()) {
100   -// tpi.tenantId(tenantId);
101   -// }
102   -// topicPartitions.add(tpi.build());
103   -// }
104   -// return topicPartitions;
105   -// }
106   -
107 89 @Override
108 90 public TopicPartitionInfo resolve(ServiceType serviceType, TenantId tenantId, EntityId entityId) {
109 91 return resolve(new ServiceQueue(serviceType), tenantId, entityId);
... ... @@ -131,15 +113,7 @@ public class ConsistentHashPartitionService implements PartitionService {
131 113 Map<ServiceQueueKey, ConsistentHashCircle<ServiceInfo>> circles = new HashMap<>();
132 114 addNode(circles, currentService);
133 115 for (ServiceInfo other : otherServices) {
134   - TenantId tenantId = getSystemOrIsolatedTenantId(other);
135 116 addNode(circles, other);
136   - if (!tenantId.isNullUid()) {
137   - isolatedTenants.putIfAbsent(tenantId, new HashSet<>());
138   - for (String serviceType : other.getServiceTypesList()) {
139   - isolatedTenants.get(tenantId).add(ServiceType.valueOf(serviceType.toUpperCase()));
140   - }
141   -
142   - }
143 117 }
144 118 ConcurrentMap<ServiceQueueKey, List<Integer>> oldPartitions = myPartitions;
145 119 TenantId myTenantId = getSystemOrIsolatedTenantId(currentService);
... ... @@ -214,6 +188,11 @@ public class ConsistentHashPartitionService implements PartitionService {
214 188 }
215 189 }
216 190
  191 + @Override
  192 + public Set<TenantId> getIsolatedTenants(ServiceType serviceType) {
  193 + throw new RuntimeException("Not Implemented!");
  194 + }
  195 +
217 196 private Map<ServiceQueueKey, List<ServiceInfo>> getServiceKeyListMap(List<ServiceInfo> services) {
218 197 final Map<ServiceQueueKey, List<ServiceInfo>> currentMap = new HashMap<>();
219 198 services.forEach(serviceInfo -> {
... ... @@ -280,6 +259,12 @@ public class ConsistentHashPartitionService implements PartitionService {
280 259
281 260 private void addNode(Map<ServiceQueueKey, ConsistentHashCircle<ServiceInfo>> circles, ServiceInfo instance) {
282 261 TenantId tenantId = getSystemOrIsolatedTenantId(instance);
  262 + if (!tenantId.isNullUid()) {
  263 + isolatedTenants.putIfAbsent(tenantId, new HashSet<>());
  264 + for (String serviceType : instance.getServiceTypesList()) {
  265 + isolatedTenants.get(tenantId).add(ServiceType.valueOf(serviceType.toUpperCase()));
  266 + }
  267 + }
283 268 for (String serviceTypeStr : instance.getServiceTypesList()) {
284 269 ServiceType serviceType = ServiceType.valueOf(serviceTypeStr.toUpperCase());
285 270 if (ServiceType.TB_RULE_ENGINE.equals(serviceType)) {
... ...
... ... @@ -34,6 +34,7 @@ import java.net.UnknownHostException;
34 34 import java.util.Arrays;
35 35 import java.util.Collections;
36 36 import java.util.List;
  37 +import java.util.Optional;
37 38 import java.util.UUID;
38 39 import java.util.stream.Collectors;
39 40
... ... @@ -58,6 +59,7 @@ public class DefaultTbServiceInfoProvider implements TbServiceInfoProvider {
58 59
59 60 private List<ServiceType> serviceTypes;
60 61 private ServiceInfo serviceInfo;
  62 + private TenantId isolatedTenant;
61 63
62 64 @PostConstruct
63 65 public void init() {
... ... @@ -80,6 +82,7 @@ public class DefaultTbServiceInfoProvider implements TbServiceInfoProvider {
80 82 UUID tenantId;
81 83 if (!StringUtils.isEmpty(tenantIdStr)) {
82 84 tenantId = UUID.fromString(tenantIdStr);
  85 + isolatedTenant = new TenantId(tenantId);
83 86 } else {
84 87 tenantId = TenantId.NULL_UUID;
85 88 }
... ... @@ -103,4 +106,14 @@ public class DefaultTbServiceInfoProvider implements TbServiceInfoProvider {
103 106 public ServiceInfo getServiceInfo() {
104 107 return serviceInfo;
105 108 }
  109 +
  110 + @Override
  111 + public boolean isService(ServiceType serviceType) {
  112 + return serviceTypes.contains(serviceType);
  113 + }
  114 +
  115 + @Override
  116 + public Optional<TenantId> getIsolatedTenant() {
  117 + return Optional.ofNullable(isolatedTenant);
  118 + }
106 119 }
... ...
... ... @@ -47,6 +47,8 @@ public interface PartitionService {
47 47 */
48 48 Set<String> getAllServiceIds(ServiceType serviceType);
49 49
  50 + Set<TenantId> getIsolatedTenants(ServiceType serviceType);
  51 +
50 52 /**
51 53 * Each Service should start a consumer for messages that target individual service instance based on serviceId.
52 54 * This topic is likely to have single partition, and is always assigned to the service.
... ...
... ... @@ -15,12 +15,20 @@
15 15 */
16 16 package org.thingsboard.server.queue.discovery;
17 17
  18 +import org.thingsboard.server.common.data.id.TenantId;
  19 +import org.thingsboard.server.common.msg.queue.ServiceType;
18 20 import org.thingsboard.server.gen.transport.TransportProtos.ServiceInfo;
19 21
  22 +import java.util.Optional;
  23 +
20 24 public interface TbServiceInfoProvider {
21 25
22 26 String getServiceId();
23 27
24 28 ServiceInfo getServiceInfo();
25 29
  30 + boolean isService(ServiceType serviceType);
  31 +
  32 + Optional<TenantId> getIsolatedTenant();
  33 +
26 34 }
... ...
... ... @@ -17,7 +17,9 @@ package org.thingsboard.server.queue.settings;
17 17
18 18 import lombok.Data;
19 19 import lombok.extern.slf4j.Slf4j;
  20 +import org.springframework.beans.factory.annotation.Autowired;
20 21 import org.springframework.beans.factory.annotation.Value;
  22 +import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
21 23 import org.springframework.boot.context.properties.ConfigurationProperties;
22 24 import org.springframework.context.annotation.Configuration;
23 25
... ... @@ -26,6 +28,7 @@ import java.util.List;
26 28
27 29 @Slf4j
28 30 @Data
  31 +@EnableAutoConfiguration
29 32 @Configuration
30 33 @ConfigurationProperties(prefix = "queue.rule-engine")
31 34 public class TbQueueRuleEngineSettings {
... ...
... ... @@ -388,6 +388,7 @@ message ToRuleEngineMsg {
388 388 int64 tenantIdLSB = 2;
389 389 bytes tbMsg = 3;
390 390 repeated string relationTypes = 4;
  391 + string failureMessage = 5;
391 392 }
392 393
393 394 message ToRuleEngineNotificationMsg {
... ...
... ... @@ -16,7 +16,6 @@
16 16 package org.thingsboard.rule.engine.api;
17 17
18 18 import org.thingsboard.server.common.msg.TbMsg;
19   -import org.thingsboard.server.common.msg.cluster.ServerAddress;
20 19
21 20 import java.util.function.Consumer;
22 21
... ... @@ -26,6 +25,4 @@ public interface RuleChainTransactionService {
26 25
27 26 void endTransaction(TbMsg msg, Consumer<TbMsg> onSuccess, Consumer<Throwable> onFailure);
28 27
29   - void onRemoteTransactionMsg(ServerAddress serverAddress, byte[] bytes);
30   -
31 28 }
... ...
... ... @@ -26,10 +26,8 @@ import org.thingsboard.server.common.data.asset.Asset;
26 26 import org.thingsboard.server.common.data.id.EntityId;
27 27 import org.thingsboard.server.common.data.id.RuleNodeId;
28 28 import org.thingsboard.server.common.data.id.TenantId;
29   -import org.thingsboard.server.common.data.rule.RuleNode;
30 29 import org.thingsboard.server.common.msg.TbMsg;
31 30 import org.thingsboard.server.common.msg.TbMsgMetaData;
32   -import org.thingsboard.server.common.msg.queue.TbMsgCallback;
33 31 import org.thingsboard.server.dao.alarm.AlarmService;
34 32 import org.thingsboard.server.dao.asset.AssetService;
35 33 import org.thingsboard.server.dao.attributes.AttributesService;
... ... @@ -116,6 +114,8 @@ public interface TbContext {
116 114 */
117 115 void enqueue(TbMsg msg, String queueName, Runnable onSuccess, Consumer<Throwable> onFailure);
118 116
  117 + void enqueueForTellFailure(TbMsg msg, String failureMessage);
  118 +
119 119 void enqueueForTellNext(TbMsg msg, String relationType);
120 120
121 121 void enqueueForTellNext(TbMsg msg, Set<String> relationTypes);
... ...
  1 +/**
  2 + * Copyright © 2016-2020 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.rule.engine.flow;
  17 +
  18 +import lombok.extern.slf4j.Slf4j;
  19 +import org.thingsboard.rule.engine.api.EmptyNodeConfiguration;
  20 +import org.thingsboard.rule.engine.api.RuleNode;
  21 +import org.thingsboard.rule.engine.api.TbContext;
  22 +import org.thingsboard.rule.engine.api.TbNode;
  23 +import org.thingsboard.rule.engine.api.TbNodeConfiguration;
  24 +import org.thingsboard.rule.engine.api.TbNodeException;
  25 +import org.thingsboard.rule.engine.api.TbRelationTypes;
  26 +import org.thingsboard.rule.engine.api.util.TbNodeUtils;
  27 +import org.thingsboard.server.common.data.plugin.ComponentType;
  28 +import org.thingsboard.server.common.msg.TbMsg;
  29 +
  30 +@Slf4j
  31 +@RuleNode(
  32 + type = ComponentType.ACTION,
  33 + name = "acknowledge",
  34 + configClazz = EmptyNodeConfiguration.class,
  35 + nodeDescription = "Acknowledges the incoming message",
  36 + nodeDetails = "After acknowledgement, the message is pushed to related rule nodes. Useful if you don't care what happens to this message next.")
  37 +
  38 +public class TbAckNode implements TbNode {
  39 +
  40 + @Override
  41 + public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException {
  42 + }
  43 +
  44 + @Override
  45 + public void onMsg(TbContext ctx, TbMsg msg) {
  46 + ctx.ack(msg);
  47 + ctx.tellSuccess(msg);
  48 + }
  49 +
  50 + @Override
  51 + public void destroy() {
  52 + }
  53 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2020 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.rule.engine.flow;
  17 +
  18 +import lombok.extern.slf4j.Slf4j;
  19 +import org.thingsboard.rule.engine.api.RuleNode;
  20 +import org.thingsboard.rule.engine.api.ScriptEngine;
  21 +import org.thingsboard.rule.engine.api.TbContext;
  22 +import org.thingsboard.rule.engine.api.TbNode;
  23 +import org.thingsboard.rule.engine.api.TbNodeConfiguration;
  24 +import org.thingsboard.rule.engine.api.TbNodeException;
  25 +import org.thingsboard.rule.engine.api.TbRelationTypes;
  26 +import org.thingsboard.rule.engine.api.util.TbNodeUtils;
  27 +import org.thingsboard.server.common.data.plugin.ComponentType;
  28 +import org.thingsboard.server.common.msg.TbMsg;
  29 +
  30 +import static org.thingsboard.common.util.DonAsynchron.withCallback;
  31 +
  32 +@Slf4j
  33 +@RuleNode(
  34 + type = ComponentType.ACTION,
  35 + name = "checkpoint",
  36 + configClazz = TbCheckpointNodeConfiguration.class,
  37 + nodeDescription = "transfers the message to another queue",
  38 + nodeDetails = "After successful transfer incoming message is automatically acknowledged. Queue name is configurable.")
  39 +
  40 +public class TbCheckpointNode implements TbNode {
  41 +
  42 + private TbCheckpointNodeConfiguration config;
  43 +
  44 + @Override
  45 + public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException {
  46 + this.config = TbNodeUtils.convert(configuration, TbCheckpointNodeConfiguration.class);
  47 + }
  48 +
  49 + @Override
  50 + public void onMsg(TbContext ctx, TbMsg msg) {
  51 + ctx.enqueueForTellNext(msg, config.getQueueName(), TbRelationTypes.SUCCESS, () -> ctx.ack(msg), error -> ctx.tellFailure(msg, error));
  52 + }
  53 +
  54 + @Override
  55 + public void destroy() {
  56 + }
  57 +}
... ...
rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/flow/TbCheckpointNodeConfiguration.java renamed from common/message/src/main/java/org/thingsboard/server/common/msg/cluster/SendToClusterMsg.java
... ... @@ -13,28 +13,20 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.common.msg.cluster;
  16 +package org.thingsboard.rule.engine.flow;
17 17
18 18 import lombok.Data;
19   -import org.thingsboard.server.common.data.id.DeviceId;
20   -import org.thingsboard.server.common.data.id.EntityId;
21   -import org.thingsboard.server.common.msg.MsgType;
22   -import org.thingsboard.server.common.msg.TbActorMsg;
  19 +import org.thingsboard.rule.engine.api.NodeConfiguration;
23 20
24 21 @Data
25   -public class SendToClusterMsg implements TbActorMsg {
26   -
27   - private TbActorMsg msg;
28   - private EntityId entityId;
29   -
30   - public SendToClusterMsg(EntityId entityId, TbActorMsg msg) {
31   - this.entityId = entityId;
32   - this.msg = msg;
33   - }
  22 +public class TbCheckpointNodeConfiguration implements NodeConfiguration<TbCheckpointNodeConfiguration> {
34 23
  24 + private String queueName;
35 25
36 26 @Override
37   - public MsgType getMsgType() {
38   - return MsgType.SEND_TO_CLUSTER_MSG;
  27 + public TbCheckpointNodeConfiguration defaultConfiguration() {
  28 + TbCheckpointNodeConfiguration configuration = new TbCheckpointNodeConfiguration();
  29 + configuration.setQueueName("HighPriority");
  30 + return configuration;
39 31 }
40 32 }
... ...
... ... @@ -116,8 +116,7 @@ public class TbSendRPCRequestNode implements TbNode {
116 116 ctx.enqueueForTellNext(next, TbRelationTypes.SUCCESS);
117 117 } else {
118 118 TbMsg next = ctx.newMsg(msg.getType(), msg.getOriginator(), msg.getMetaData(), wrap("error", ruleEngineDeviceRpcResponse.getError().get().name()));
119   - ctx.tellFailure(next, new RuntimeException(ruleEngineDeviceRpcResponse.getError().get().name()));
120   - ctx.enqueueForTellNext(next, TbRelationTypes.FAILURE);
  119 + ctx.enqueueForTellFailure(next, ruleEngineDeviceRpcResponse.getError().get().name());
121 120 }
122 121 });
123 122 ctx.ack(msg);
... ...
... ... @@ -102,20 +102,44 @@ queue:
102 102 stats:
103 103 enabled: "${TB_QUEUE_CORE_STATS_ENABLED:false}"
104 104 print_interval_ms: "${TB_QUEUE_CORE_STATS_PRINT_INTERVAL_MS:10000}"
105   - rule_engine:
  105 + rule-engine:
106 106 topic: "${TB_QUEUE_RULE_ENGINE_TOPIC:tb.rule-engine}"
107   - poll_interval: "${TB_QUEUE_RULE_ENGINE_POLL_INTERVAL_MS:25}"
108   - partitions: "${TB_QUEUE_RULE_ENGINE_PARTITIONS:10}"
109   - pack_processing_timeout: "${TB_QUEUE_RULE_ENGINE_PACK_PROCESSING_TIMEOUT_MS:60000}"
  107 + poll-interval: "${TB_QUEUE_RULE_ENGINE_POLL_INTERVAL_MS:25}"
  108 + pack-processing-timeout: "${TB_QUEUE_RULE_ENGINE_PACK_PROCESSING_TIMEOUT_MS:60000}"
110 109 stats:
111   - enabled: "${TB_QUEUE_RULE_ENGINE_STATS_ENABLED:false}"
112   - print_interval_ms: "${TB_QUEUE_RULE_ENGINE_STATS_PRINT_INTERVAL_MS:10000}"
  110 + enabled: "${TB_QUEUE_RULE_ENGINE_STATS_ENABLED:true}"
  111 + print-interval-ms: "${TB_QUEUE_RULE_ENGINE_STATS_PRINT_INTERVAL_MS:10000}"
  112 + queues: # TODO 2.5: specify correct ENV variable names.
  113 + -
  114 + name: "Main"
  115 + topic: "${TB_QUEUE_RULE_ENGINE_TOPIC:tb.rule-engine.main}"
  116 + poll-interval: "${TB_QUEUE_RULE_ENGINE_POLL_INTERVAL_MS:25}"
  117 + partitions: "${TB_QUEUE_RULE_ENGINE_PARTITIONS:10}"
  118 + pack-processing-timeout: "${TB_QUEUE_RULE_ENGINE_PACK_PROCESSING_TIMEOUT_MS:60000}"
  119 + ack-strategy:
  120 + type: "${TB_QUEUE_RULE_ENGINE_STRATEGY_TYPE:RETRY_FAILED_AND_TIMED_OUT}" # SKIP_ALL_FAILURES, RETRY_ALL, RETRY_FAILED, RETRY_TIMED_OUT, RETRY_FAILED_AND_TIMED_OUT
  121 + # For RETRY_ALL, RETRY_FAILED, RETRY_TIMED_OUT, RETRY_FAILED_AND_TIMED_OUT
  122 + retries: "${TB_QUEUE_RULE_ENGINE_STRATEGY_RETRIES:3}" # Number of retries, 0 is unlimited
  123 + failure-percentage: "${TB_QUEUE_RULE_ENGINE_STRATEGY_FAILURE_PERCENTAGE:0}" # Skip retry if failures or timeouts are less then X percentage of messages;
  124 + pause-between-retries: "${TB_QUEUE_RULE_ENGINE_STRATEGY_RETRY_PAUSE:3}"# Time in seconds to wait in consumer thread before retries;
  125 + -
  126 + name: "HighPriority"
  127 + topic: "${TB_QUEUE_RULE_ENGINE_TOPIC:tb.rule-engine.hp}"
  128 + poll-interval: "${TB_QUEUE_RULE_ENGINE_POLL_INTERVAL_MS:25}"
  129 + partitions: "${TB_QUEUE_RULE_ENGINE_PARTITIONS:3}"
  130 + pack-processing-timeout: "${TB_QUEUE_RULE_ENGINE_PACK_PROCESSING_TIMEOUT_MS:60000}"
  131 + ack-strategy:
  132 + type: "${TB_QUEUE_RULE_ENGINE_STRATEGY_TYPE:RETRY_FAILED_AND_TIMED_OUT}" # SKIP_ALL_FAILURES, RETRY_ALL, RETRY_FAILED, RETRY_TIMED_OUT, RETRY_FAILED_AND_TIMED_OUT
  133 + # For RETRY_ALL, RETRY_FAILED, RETRY_TIMED_OUT, RETRY_FAILED_AND_TIMED_OUT
  134 + retries: "${TB_QUEUE_RULE_ENGINE_STRATEGY_RETRIES:0}" # Number of retries, 0 is unlimited
  135 + failure-percentage: "${TB_QUEUE_RULE_ENGINE_STRATEGY_FAILURE_PERCENTAGE:0}" # Skip retry if failures or timeouts are less then X percentage of messages;
  136 + pause-between-retries: "${TB_QUEUE_RULE_ENGINE_STRATEGY_RETRY_PAUSE:1}"# Time in seconds to wait in consumer thread before retries;
113 137 transport:
114 138 notifications_topic: "${TB_QUEUE_TRANSPORT_NOTIFICATIONS_TOPIC:tb.transport.notifications}"
115 139 poll_interval: "${TB_QUEUE_CORE_POLL_INTERVAL_MS:25}"
116 140
117 141 service:
118   - type: "${TB_SERVICE_TYPE:tb-transport}" # monolith or tb-core or tb-rule-engine or tb-transport
  142 + type: "${TB_SERVICE_TYPE:tb-transport}"
119 143 # Unique id for this service (autogenerated if empty)
120 144 id: "${TB_SERVICE_ID:}"
121 145 tenant_id: "${TB_SERVICE_TENANT_ID:}" # empty or specific tenant id.
\ No newline at end of file
... ...