Commit 21ee2aec11ae5bf0d0660001987cfeb4b8ba4cea

Authored by Volodymyr Babak
2 parents 8462481e 8d9a5875

Merge remote-tracking branch 'upstream/develop/2.5.3' into feature/edge

Showing 88 changed files with 2264 additions and 742 deletions

Too many changes to show.

To preserve performance only 88 of 132 files are displayed.

@@ -20,7 +20,7 @@ @@ -20,7 +20,7 @@
20 <modelVersion>4.0.0</modelVersion> 20 <modelVersion>4.0.0</modelVersion>
21 <parent> 21 <parent>
22 <groupId>org.thingsboard</groupId> 22 <groupId>org.thingsboard</groupId>
23 - <version>2.5.1-SNAPSHOT</version> 23 + <version>2.5.3-SNAPSHOT</version>
24 <artifactId>thingsboard</artifactId> 24 <artifactId>thingsboard</artifactId>
25 </parent> 25 </parent>
26 <artifactId>application</artifactId> 26 <artifactId>application</artifactId>
@@ -59,6 +59,10 @@ @@ -59,6 +59,10 @@
59 </dependency> 59 </dependency>
60 <dependency> 60 <dependency>
61 <groupId>org.thingsboard.common</groupId> 61 <groupId>org.thingsboard.common</groupId>
  62 + <artifactId>actor</artifactId>
  63 + </dependency>
  64 + <dependency>
  65 + <groupId>org.thingsboard.common</groupId>
62 <artifactId>util</artifactId> 66 <artifactId>util</artifactId>
63 </dependency> 67 </dependency>
64 <dependency> 68 <dependency>
@@ -178,14 +182,6 @@ @@ -178,14 +182,6 @@
178 <artifactId>spring-context-support</artifactId> 182 <artifactId>spring-context-support</artifactId>
179 </dependency> 183 </dependency>
180 <dependency> 184 <dependency>
181 - <groupId>com.typesafe.akka</groupId>  
182 - <artifactId>akka-actor_${scala.version}</artifactId>  
183 - </dependency>  
184 - <dependency>  
185 - <groupId>com.typesafe.akka</groupId>  
186 - <artifactId>akka-slf4j_${scala.version}</artifactId>  
187 - </dependency>  
188 - <dependency>  
189 <groupId>org.slf4j</groupId> 185 <groupId>org.slf4j</groupId>
190 <artifactId>slf4j-api</artifactId> 186 <artifactId>slf4j-api</artifactId>
191 </dependency> 187 </dependency>
@@ -375,7 +371,7 @@ @@ -375,7 +371,7 @@
375 <repository> 371 <repository>
376 <id>jenkins</id> 372 <id>jenkins</id>
377 <name>Jenkins Repository</name> 373 <name>Jenkins Repository</name>
378 - <url>http://repo.jenkins-ci.org/releases</url> 374 + <url>https://repo.jenkins-ci.org/releases</url>
379 <snapshots> 375 <snapshots>
380 <enabled>false</enabled> 376 <enabled>false</enabled>
381 </snapshots> 377 </snapshots>
@@ -35,7 +35,6 @@ @@ -35,7 +35,6 @@
35 </appender> 35 </appender>
36 36
37 <logger name="org.thingsboard.server" level="INFO" /> 37 <logger name="org.thingsboard.server" level="INFO" />
38 - <logger name="akka" level="INFO" />  
39 <logger name="com.microsoft.azure.servicebus.primitives.CoreMessageReceiver" level="OFF" /> 38 <logger name="com.microsoft.azure.servicebus.primitives.CoreMessageReceiver" level="OFF" />
40 39
41 <root level="INFO"> 40 <root level="INFO">
@@ -15,9 +15,6 @@ @@ -15,9 +15,6 @@
15 */ 15 */
16 package org.thingsboard.server.actors; 16 package org.thingsboard.server.actors;
17 17
18 -import akka.actor.ActorRef;  
19 -import akka.actor.ActorSystem;  
20 -import akka.actor.Scheduler;  
21 import com.fasterxml.jackson.databind.JsonNode; 18 import com.fasterxml.jackson.databind.JsonNode;
22 import com.fasterxml.jackson.databind.ObjectMapper; 19 import com.fasterxml.jackson.databind.ObjectMapper;
23 import com.fasterxml.jackson.databind.node.ObjectNode; 20 import com.fasterxml.jackson.databind.node.ObjectNode;
@@ -25,8 +22,6 @@ import com.google.common.util.concurrent.FutureCallback; @@ -25,8 +22,6 @@ import com.google.common.util.concurrent.FutureCallback;
25 import com.google.common.util.concurrent.Futures; 22 import com.google.common.util.concurrent.Futures;
26 import com.google.common.util.concurrent.ListenableFuture; 23 import com.google.common.util.concurrent.ListenableFuture;
27 import com.google.common.util.concurrent.MoreExecutors; 24 import com.google.common.util.concurrent.MoreExecutors;
28 -import com.typesafe.config.Config;  
29 -import com.typesafe.config.ConfigFactory;  
30 import lombok.Getter; 25 import lombok.Getter;
31 import lombok.Setter; 26 import lombok.Setter;
32 import lombok.extern.slf4j.Slf4j; 27 import lombok.extern.slf4j.Slf4j;
@@ -93,12 +88,13 @@ import java.io.StringWriter; @@ -93,12 +88,13 @@ import java.io.StringWriter;
93 import java.util.Optional; 88 import java.util.Optional;
94 import java.util.concurrent.ConcurrentHashMap; 89 import java.util.concurrent.ConcurrentHashMap;
95 import java.util.concurrent.ConcurrentMap; 90 import java.util.concurrent.ConcurrentMap;
  91 +import java.util.concurrent.ScheduledExecutorService;
  92 +import java.util.concurrent.TimeUnit;
96 import java.util.concurrent.atomic.AtomicInteger; 93 import java.util.concurrent.atomic.AtomicInteger;
97 94
98 @Slf4j 95 @Slf4j
99 @Component 96 @Component
100 public class ActorSystemContext { 97 public class ActorSystemContext {
101 - private static final String AKKA_CONF_FILE_NAME = "actor-system.conf";  
102 98
103 protected final ObjectMapper mapper = new ObjectMapper(); 99 protected final ObjectMapper mapper = new ObjectMapper();
104 100
@@ -272,14 +268,6 @@ public class ActorSystemContext { @@ -272,14 +268,6 @@ public class ActorSystemContext {
272 @Getter 268 @Getter
273 private long syncSessionTimeout; 269 private long syncSessionTimeout;
274 270
275 - @Value("${actors.queue.enabled}")  
276 - @Getter  
277 - private boolean queuePersistenceEnabled;  
278 -  
279 - @Value("${actors.queue.timeout}")  
280 - @Getter  
281 - private long queuePersistenceTimeout;  
282 -  
283 @Value("${actors.rule.chain.error_persist_frequency}") 271 @Value("${actors.rule.chain.error_persist_frequency}")
284 @Getter 272 @Getter
285 private long ruleChainErrorPersistFrequency; 273 private long ruleChainErrorPersistFrequency;
@@ -339,17 +327,14 @@ public class ActorSystemContext { @@ -339,17 +327,14 @@ public class ActorSystemContext {
339 327
340 @Getter 328 @Getter
341 @Setter 329 @Setter
342 - private ActorSystem actorSystem; 330 + private TbActorSystem actorSystem;
343 331
344 @Setter 332 @Setter
345 - private ActorRef appActor; 333 + private TbActorRef appActor;
346 334
347 @Getter 335 @Getter
348 @Setter 336 @Setter
349 - private ActorRef statsActor;  
350 -  
351 - @Getter  
352 - private final Config config; 337 + private TbActorRef statsActor;
353 338
354 @Autowired(required = false) 339 @Autowired(required = false)
355 @Getter 340 @Getter
@@ -363,14 +348,8 @@ public class ActorSystemContext { @@ -363,14 +348,8 @@ public class ActorSystemContext {
363 @Getter 348 @Getter
364 private RedisTemplate<String, Object> redisTemplate; 349 private RedisTemplate<String, Object> redisTemplate;
365 350
366 - public ActorSystemContext() {  
367 - config = ConfigFactory.parseResources(AKKA_CONF_FILE_NAME).withFallback(ConfigFactory.load());  
368 - }  
369 -  
370 -  
371 -  
372 - public Scheduler getScheduler() {  
373 - return actorSystem.scheduler(); 351 + public ScheduledExecutorService getScheduler() {
  352 + return actorSystem.getScheduler();
374 } 353 }
375 354
376 public void persistError(TenantId tenantId, EntityId entityId, String method, Exception e) { 355 public void persistError(TenantId tenantId, EntityId entityId, String method, Exception e) {
@@ -543,7 +522,21 @@ public class ActorSystemContext { @@ -543,7 +522,21 @@ public class ActorSystemContext {
543 return Exception.class.isInstance(error) ? (Exception) error : new Exception(error); 522 return Exception.class.isInstance(error) ? (Exception) error : new Exception(error);
544 } 523 }
545 524
546 - public void tell(TbActorMsg tbActorMsg, ActorRef sender) {  
547 - appActor.tell(tbActorMsg, sender); 525 + public void tell(TbActorMsg tbActorMsg) {
  526 + appActor.tell(tbActorMsg);
  527 + }
  528 +
  529 + public void tellWithHighPriority(TbActorMsg tbActorMsg) {
  530 + appActor.tellWithHighPriority(tbActorMsg);
  531 + }
  532 +
  533 + public void schedulePeriodicMsgWithDelay(TbActorRef ctx, TbActorMsg msg, long delayInMs, long periodInMs) {
  534 + log.debug("Scheduling periodic msg {} every {} ms with delay {} ms", msg, periodInMs, delayInMs);
  535 + getScheduler().scheduleWithFixedDelay(() -> ctx.tell(msg), delayInMs, periodInMs, TimeUnit.MILLISECONDS);
  536 + }
  537 +
  538 + public void scheduleMsgWithDelay(TbActorRef ctx, TbActorMsg msg, long delayInMs) {
  539 + log.debug("Scheduling msg {} with delay {} ms", msg, delayInMs);
  540 + getScheduler().schedule(() -> ctx.tell(msg), delayInMs, TimeUnit.MILLISECONDS);
548 } 541 }
549 } 542 }
  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;
  17 +
  18 +import lombok.RequiredArgsConstructor;
  19 +import org.thingsboard.server.common.data.EntityType;
  20 +import org.thingsboard.server.common.data.id.EntityId;
  21 +
  22 +import java.util.function.Predicate;
  23 +
  24 +@RequiredArgsConstructor
  25 +public class TbEntityTypeActorIdPredicate implements Predicate<TbActorId> {
  26 +
  27 + private final EntityType entityType;
  28 +
  29 + @Override
  30 + public boolean test(TbActorId actorId) {
  31 + return actorId instanceof TbEntityActorId && testEntityId(((TbEntityActorId) actorId).getEntityId());
  32 + }
  33 +
  34 + protected boolean testEntityId(EntityId entityId) {
  35 + return entityId.getEntityType().equals(entityType);
  36 + }
  37 +}
@@ -15,21 +15,19 @@ @@ -15,21 +15,19 @@
15 */ 15 */
16 package org.thingsboard.server.actors.app; 16 package org.thingsboard.server.actors.app;
17 17
18 -import akka.actor.ActorRef;  
19 -import akka.actor.LocalActorRef;  
20 -import akka.actor.OneForOneStrategy;  
21 -import akka.actor.Props;  
22 -import akka.actor.SupervisorStrategy;  
23 -import akka.actor.Terminated;  
24 -import com.google.common.collect.BiMap;  
25 -import com.google.common.collect.HashBiMap; 18 +import lombok.extern.slf4j.Slf4j;
26 import org.thingsboard.server.actors.ActorSystemContext; 19 import org.thingsboard.server.actors.ActorSystemContext;
  20 +import org.thingsboard.server.actors.TbActor;
  21 +import org.thingsboard.server.actors.TbActorId;
  22 +import org.thingsboard.server.actors.TbActorRef;
  23 +import org.thingsboard.server.actors.TbEntityActorId;
27 import org.thingsboard.server.actors.service.ContextAwareActor; 24 import org.thingsboard.server.actors.service.ContextAwareActor;
28 import org.thingsboard.server.actors.service.ContextBasedCreator; 25 import org.thingsboard.server.actors.service.ContextBasedCreator;
29 import org.thingsboard.server.actors.service.DefaultActorService; 26 import org.thingsboard.server.actors.service.DefaultActorService;
30 import org.thingsboard.server.actors.tenant.TenantActor; 27 import org.thingsboard.server.actors.tenant.TenantActor;
31 import org.thingsboard.server.common.data.EntityType; 28 import org.thingsboard.server.common.data.EntityType;
32 import org.thingsboard.server.common.data.Tenant; 29 import org.thingsboard.server.common.data.Tenant;
  30 +import org.thingsboard.server.common.data.id.EntityId;
33 import org.thingsboard.server.common.data.id.TenantId; 31 import org.thingsboard.server.common.data.id.TenantId;
34 import org.thingsboard.server.common.data.page.PageDataIterable; 32 import org.thingsboard.server.common.data.page.PageDataIterable;
35 import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; 33 import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
@@ -43,38 +41,27 @@ import org.thingsboard.server.common.msg.queue.ServiceType; @@ -43,38 +41,27 @@ import org.thingsboard.server.common.msg.queue.ServiceType;
43 import org.thingsboard.server.dao.model.ModelConstants; 41 import org.thingsboard.server.dao.model.ModelConstants;
44 import org.thingsboard.server.dao.tenant.TenantService; 42 import org.thingsboard.server.dao.tenant.TenantService;
45 import org.thingsboard.server.service.transport.msg.TransportToDeviceActorMsgWrapper; 43 import org.thingsboard.server.service.transport.msg.TransportToDeviceActorMsgWrapper;
46 -import scala.concurrent.duration.Duration;  
47 44
48 import java.util.HashSet; 45 import java.util.HashSet;
49 import java.util.Optional; 46 import java.util.Optional;
50 import java.util.Set; 47 import java.util.Set;
51 48
  49 +@Slf4j
52 public class AppActor extends ContextAwareActor { 50 public class AppActor extends ContextAwareActor {
53 51
54 private static final TenantId SYSTEM_TENANT = new TenantId(ModelConstants.NULL_UUID); 52 private static final TenantId SYSTEM_TENANT = new TenantId(ModelConstants.NULL_UUID);
55 private final TenantService tenantService; 53 private final TenantService tenantService;
56 - private final BiMap<TenantId, ActorRef> tenantActors;  
57 private final Set<TenantId> deletedTenants; 54 private final Set<TenantId> deletedTenants;
58 private boolean ruleChainsInitialized; 55 private boolean ruleChainsInitialized;
59 56
60 private AppActor(ActorSystemContext systemContext) { 57 private AppActor(ActorSystemContext systemContext) {
61 super(systemContext); 58 super(systemContext);
62 this.tenantService = systemContext.getTenantService(); 59 this.tenantService = systemContext.getTenantService();
63 - this.tenantActors = HashBiMap.create();  
64 this.deletedTenants = new HashSet<>(); 60 this.deletedTenants = new HashSet<>();
65 } 61 }
66 62
67 @Override 63 @Override
68 - public SupervisorStrategy supervisorStrategy() {  
69 - return strategy;  
70 - }  
71 -  
72 - @Override  
73 - public void preStart() {  
74 - }  
75 -  
76 - @Override  
77 - protected boolean process(TbActorMsg msg) { 64 + protected boolean doProcess(TbActorMsg msg) {
78 if (!ruleChainsInitialized) { 65 if (!ruleChainsInitialized) {
79 initTenantActors(); 66 initTenantActors();
80 ruleChainsInitialized = true; 67 ruleChainsInitialized = true;
@@ -86,7 +73,7 @@ public class AppActor extends ContextAwareActor { @@ -86,7 +73,7 @@ public class AppActor extends ContextAwareActor {
86 case APP_INIT_MSG: 73 case APP_INIT_MSG:
87 break; 74 break;
88 case PARTITION_CHANGE_MSG: 75 case PARTITION_CHANGE_MSG:
89 - broadcast(msg); 76 + ctx.broadcastToChildren(msg);
90 break; 77 break;
91 case COMPONENT_LIFE_CYCLE_MSG: 78 case COMPONENT_LIFE_CYCLE_MSG:
92 onComponentLifecycleMsg((ComponentLifecycleMsg) msg); 79 onComponentLifecycleMsg((ComponentLifecycleMsg) msg);
@@ -95,12 +82,14 @@ public class AppActor extends ContextAwareActor { @@ -95,12 +82,14 @@ public class AppActor extends ContextAwareActor {
95 onQueueToRuleEngineMsg((QueueToRuleEngineMsg) msg); 82 onQueueToRuleEngineMsg((QueueToRuleEngineMsg) msg);
96 break; 83 break;
97 case TRANSPORT_TO_DEVICE_ACTOR_MSG: 84 case TRANSPORT_TO_DEVICE_ACTOR_MSG:
  85 + onToDeviceActorMsg((TenantAwareMsg) msg, false);
  86 + break;
98 case DEVICE_ATTRIBUTES_UPDATE_TO_DEVICE_ACTOR_MSG: 87 case DEVICE_ATTRIBUTES_UPDATE_TO_DEVICE_ACTOR_MSG:
99 case DEVICE_CREDENTIALS_UPDATE_TO_DEVICE_ACTOR_MSG: 88 case DEVICE_CREDENTIALS_UPDATE_TO_DEVICE_ACTOR_MSG:
100 case DEVICE_NAME_OR_TYPE_UPDATE_TO_DEVICE_ACTOR_MSG: 89 case DEVICE_NAME_OR_TYPE_UPDATE_TO_DEVICE_ACTOR_MSG:
101 case DEVICE_RPC_REQUEST_TO_DEVICE_ACTOR_MSG: 90 case DEVICE_RPC_REQUEST_TO_DEVICE_ACTOR_MSG:
102 case SERVER_RPC_RESPONSE_TO_DEVICE_ACTOR_MSG: 91 case SERVER_RPC_RESPONSE_TO_DEVICE_ACTOR_MSG:
103 - onToDeviceActorMsg((TenantAwareMsg) msg); 92 + onToDeviceActorMsg((TenantAwareMsg) msg, true);
104 break; 93 break;
105 default: 94 default:
106 return false; 95 return false;
@@ -145,19 +134,15 @@ public class AppActor extends ContextAwareActor { @@ -145,19 +134,15 @@ public class AppActor extends ContextAwareActor {
145 msg.getTbMsg().getCallback().onFailure(new RuleEngineException("Message has system tenant id!")); 134 msg.getTbMsg().getCallback().onFailure(new RuleEngineException("Message has system tenant id!"));
146 } else { 135 } else {
147 if (!deletedTenants.contains(msg.getTenantId())) { 136 if (!deletedTenants.contains(msg.getTenantId())) {
148 - getOrCreateTenantActor(msg.getTenantId()).tell(msg, self()); 137 + getOrCreateTenantActor(msg.getTenantId()).tell(msg);
149 } else { 138 } else {
150 msg.getTbMsg().getCallback().onSuccess(); 139 msg.getTbMsg().getCallback().onSuccess();
151 } 140 }
152 } 141 }
153 } 142 }
154 143
155 - protected void broadcast(Object msg) {  
156 - tenantActors.values().forEach(actorRef -> actorRef.tell(msg, ActorRef.noSender()));  
157 - }  
158 -  
159 private void onComponentLifecycleMsg(ComponentLifecycleMsg msg) { 144 private void onComponentLifecycleMsg(ComponentLifecycleMsg msg) {
160 - ActorRef target = null; 145 + TbActorRef target = null;
161 if (SYSTEM_TENANT.equals(msg.getTenantId())) { 146 if (SYSTEM_TENANT.equals(msg.getTenantId())) {
162 log.warn("Message has system tenant id: {}", msg); 147 log.warn("Message has system tenant id: {}", msg);
163 } else { 148 } else {
@@ -166,25 +151,26 @@ public class AppActor extends ContextAwareActor { @@ -166,25 +151,26 @@ public class AppActor extends ContextAwareActor {
166 log.info("[{}] Handling tenant deleted notification: {}", msg.getTenantId(), msg); 151 log.info("[{}] Handling tenant deleted notification: {}", msg.getTenantId(), msg);
167 TenantId tenantId = new TenantId(msg.getEntityId().getId()); 152 TenantId tenantId = new TenantId(msg.getEntityId().getId());
168 deletedTenants.add(tenantId); 153 deletedTenants.add(tenantId);
169 - ActorRef tenantActor = tenantActors.get(tenantId);  
170 - if (tenantActor != null) {  
171 - log.debug("[{}] Deleting tenant actor: {}", msg.getTenantId(), tenantActor);  
172 - context().stop(tenantActor);  
173 - } 154 + ctx.stop(new TbEntityActorId(tenantId));
174 } else { 155 } else {
175 target = getOrCreateTenantActor(msg.getTenantId()); 156 target = getOrCreateTenantActor(msg.getTenantId());
176 } 157 }
177 } 158 }
178 if (target != null) { 159 if (target != null) {
179 - target.tell(msg, ActorRef.noSender()); 160 + target.tellWithHighPriority(msg);
180 } else { 161 } else {
181 log.debug("[{}] Invalid component lifecycle msg: {}", msg.getTenantId(), msg); 162 log.debug("[{}] Invalid component lifecycle msg: {}", msg.getTenantId(), msg);
182 } 163 }
183 } 164 }
184 165
185 - private void onToDeviceActorMsg(TenantAwareMsg msg) { 166 + private void onToDeviceActorMsg(TenantAwareMsg msg, boolean priority) {
186 if (!deletedTenants.contains(msg.getTenantId())) { 167 if (!deletedTenants.contains(msg.getTenantId())) {
187 - getOrCreateTenantActor(msg.getTenantId()).tell(msg, ActorRef.noSender()); 168 + TbActorRef tenantActor = getOrCreateTenantActor(msg.getTenantId());
  169 + if (priority) {
  170 + tenantActor.tellWithHighPriority(msg);
  171 + } else {
  172 + tenantActor.tell(msg);
  173 + }
188 } else { 174 } else {
189 if (msg instanceof TransportToDeviceActorMsgWrapper) { 175 if (msg instanceof TransportToDeviceActorMsgWrapper) {
190 ((TransportToDeviceActorMsgWrapper) msg).getCallback().onSuccess(); 176 ((TransportToDeviceActorMsgWrapper) msg).getCallback().onSuccess();
@@ -192,49 +178,27 @@ public class AppActor extends ContextAwareActor { @@ -192,49 +178,27 @@ public class AppActor extends ContextAwareActor {
192 } 178 }
193 } 179 }
194 180
195 - private ActorRef getOrCreateTenantActor(TenantId tenantId) {  
196 - return tenantActors.computeIfAbsent(tenantId, k -> {  
197 - log.info("[{}] Creating tenant actor.", tenantId);  
198 - ActorRef tenantActor = context().actorOf(Props.create(new TenantActor.ActorCreator(systemContext, tenantId))  
199 - .withDispatcher(DefaultActorService.CORE_DISPATCHER_NAME), tenantId.toString());  
200 - context().watch(tenantActor);  
201 - log.info("[{}] Created tenant actor: {}.", tenantId, tenantActor);  
202 - return tenantActor;  
203 - }); 181 + private TbActorRef getOrCreateTenantActor(TenantId tenantId) {
  182 + return ctx.getOrCreateChildActor(new TbEntityActorId(tenantId),
  183 + () -> DefaultActorService.TENANT_DISPATCHER_NAME,
  184 + () -> new TenantActor.ActorCreator(systemContext, tenantId));
204 } 185 }
205 186
206 - @Override  
207 - protected void processTermination(Terminated message) {  
208 - ActorRef terminated = message.actor();  
209 - if (terminated instanceof LocalActorRef) {  
210 - boolean removed = tenantActors.inverse().remove(terminated) != null;  
211 - if (removed) {  
212 - log.debug("[{}] Removed actor:", terminated);  
213 - }  
214 - } else {  
215 - throw new IllegalStateException("Remote actors are not supported!");  
216 - }  
217 - }  
218 -  
219 - public static class ActorCreator extends ContextBasedCreator<AppActor> {  
220 - private static final long serialVersionUID = 1L; 187 + public static class ActorCreator extends ContextBasedCreator {
221 188
222 public ActorCreator(ActorSystemContext context) { 189 public ActorCreator(ActorSystemContext context) {
223 super(context); 190 super(context);
224 } 191 }
225 192
226 @Override 193 @Override
227 - public AppActor create() { 194 + public TbActorId createActorId() {
  195 + return new TbEntityActorId(new TenantId(EntityId.NULL_UUID));
  196 + }
  197 +
  198 + @Override
  199 + public TbActor createActor() {
228 return new AppActor(context); 200 return new AppActor(context);
229 } 201 }
230 } 202 }
231 203
232 - private final SupervisorStrategy strategy = new OneForOneStrategy(3, Duration.create("1 minute"), t -> {  
233 - log.warn("Unknown failure", t);  
234 - if (t instanceof RuntimeException) {  
235 - return SupervisorStrategy.restart();  
236 - } else {  
237 - return SupervisorStrategy.stop();  
238 - }  
239 - });  
240 } 204 }
@@ -15,9 +15,12 @@ @@ -15,9 +15,12 @@
15 */ 15 */
16 package org.thingsboard.server.actors.device; 16 package org.thingsboard.server.actors.device;
17 17
  18 +import lombok.extern.slf4j.Slf4j;
18 import org.thingsboard.rule.engine.api.msg.DeviceAttributesEventNotificationMsg; 19 import org.thingsboard.rule.engine.api.msg.DeviceAttributesEventNotificationMsg;
19 import org.thingsboard.rule.engine.api.msg.DeviceNameOrTypeUpdateMsg; 20 import org.thingsboard.rule.engine.api.msg.DeviceNameOrTypeUpdateMsg;
20 import org.thingsboard.server.actors.ActorSystemContext; 21 import org.thingsboard.server.actors.ActorSystemContext;
  22 +import org.thingsboard.server.actors.TbActorCtx;
  23 +import org.thingsboard.server.actors.TbActorException;
21 import org.thingsboard.server.actors.service.ContextAwareActor; 24 import org.thingsboard.server.actors.service.ContextAwareActor;
22 import org.thingsboard.server.common.data.id.DeviceId; 25 import org.thingsboard.server.common.data.id.DeviceId;
23 import org.thingsboard.server.common.data.id.TenantId; 26 import org.thingsboard.server.common.data.id.TenantId;
@@ -26,6 +29,7 @@ import org.thingsboard.server.common.msg.timeout.DeviceActorServerSideRpcTimeout @@ -26,6 +29,7 @@ import org.thingsboard.server.common.msg.timeout.DeviceActorServerSideRpcTimeout
26 import org.thingsboard.server.service.rpc.ToDeviceRpcRequestActorMsg; 29 import org.thingsboard.server.service.rpc.ToDeviceRpcRequestActorMsg;
27 import org.thingsboard.server.service.transport.msg.TransportToDeviceActorMsgWrapper; 30 import org.thingsboard.server.service.transport.msg.TransportToDeviceActorMsgWrapper;
28 31
  32 +@Slf4j
29 public class DeviceActor extends ContextAwareActor { 33 public class DeviceActor extends ContextAwareActor {
30 34
31 private final DeviceActorMessageProcessor processor; 35 private final DeviceActorMessageProcessor processor;
@@ -36,29 +40,26 @@ public class DeviceActor extends ContextAwareActor { @@ -36,29 +40,26 @@ public class DeviceActor extends ContextAwareActor {
36 } 40 }
37 41
38 @Override 42 @Override
39 - public void preStart() { 43 + public void init(TbActorCtx ctx) throws TbActorException {
  44 + super.init(ctx);
40 log.debug("[{}][{}] Starting device actor.", processor.tenantId, processor.deviceId); 45 log.debug("[{}][{}] Starting device actor.", processor.tenantId, processor.deviceId);
41 try { 46 try {
42 - processor.initSessionTimeout(context()); 47 + processor.initSessionTimeout(ctx);
43 log.debug("[{}][{}] Device actor started.", processor.tenantId, processor.deviceId); 48 log.debug("[{}][{}] Device actor started.", processor.tenantId, processor.deviceId);
44 } catch (Exception e) { 49 } catch (Exception e) {
45 log.warn("[{}][{}] Unknown failure", processor.tenantId, processor.deviceId, e); 50 log.warn("[{}][{}] Unknown failure", processor.tenantId, processor.deviceId, e);
  51 + throw new TbActorException("Failed to initialize device actor", e);
46 } 52 }
47 } 53 }
48 54
49 @Override 55 @Override
50 - public void postStop() {  
51 -  
52 - }  
53 -  
54 - @Override  
55 - protected boolean process(TbActorMsg msg) { 56 + protected boolean doProcess(TbActorMsg msg) {
56 switch (msg.getMsgType()) { 57 switch (msg.getMsgType()) {
57 case TRANSPORT_TO_DEVICE_ACTOR_MSG: 58 case TRANSPORT_TO_DEVICE_ACTOR_MSG:
58 - processor.process(context(), (TransportToDeviceActorMsgWrapper) msg); 59 + processor.process(ctx, (TransportToDeviceActorMsgWrapper) msg);
59 break; 60 break;
60 case DEVICE_ATTRIBUTES_UPDATE_TO_DEVICE_ACTOR_MSG: 61 case DEVICE_ATTRIBUTES_UPDATE_TO_DEVICE_ACTOR_MSG:
61 - processor.processAttributesUpdate(context(), (DeviceAttributesEventNotificationMsg) msg); 62 + processor.processAttributesUpdate(ctx, (DeviceAttributesEventNotificationMsg) msg);
62 break; 63 break;
63 case DEVICE_CREDENTIALS_UPDATE_TO_DEVICE_ACTOR_MSG: 64 case DEVICE_CREDENTIALS_UPDATE_TO_DEVICE_ACTOR_MSG:
64 processor.processCredentialsUpdate(); 65 processor.processCredentialsUpdate();
@@ -67,10 +68,10 @@ public class DeviceActor extends ContextAwareActor { @@ -67,10 +68,10 @@ public class DeviceActor extends ContextAwareActor {
67 processor.processNameOrTypeUpdate((DeviceNameOrTypeUpdateMsg) msg); 68 processor.processNameOrTypeUpdate((DeviceNameOrTypeUpdateMsg) msg);
68 break; 69 break;
69 case DEVICE_RPC_REQUEST_TO_DEVICE_ACTOR_MSG: 70 case DEVICE_RPC_REQUEST_TO_DEVICE_ACTOR_MSG:
70 - processor.processRpcRequest(context(), (ToDeviceRpcRequestActorMsg) msg); 71 + processor.processRpcRequest(ctx, (ToDeviceRpcRequestActorMsg) msg);
71 break; 72 break;
72 case DEVICE_ACTOR_SERVER_SIDE_RPC_TIMEOUT_MSG: 73 case DEVICE_ACTOR_SERVER_SIDE_RPC_TIMEOUT_MSG:
73 - processor.processServerSideRpcTimeout(context(), (DeviceActorServerSideRpcTimeoutMsg) msg); 74 + processor.processServerSideRpcTimeout(ctx, (DeviceActorServerSideRpcTimeoutMsg) msg);
74 break; 75 break;
75 case SESSION_TIMEOUT_MSG: 76 case SESSION_TIMEOUT_MSG:
76 processor.checkSessionsTimeout(); 77 processor.checkSessionsTimeout();
@@ -16,12 +16,14 @@ @@ -16,12 +16,14 @@
16 package org.thingsboard.server.actors.device; 16 package org.thingsboard.server.actors.device;
17 17
18 import org.thingsboard.server.actors.ActorSystemContext; 18 import org.thingsboard.server.actors.ActorSystemContext;
  19 +import org.thingsboard.server.actors.TbActor;
  20 +import org.thingsboard.server.actors.TbActorId;
  21 +import org.thingsboard.server.actors.TbEntityActorId;
19 import org.thingsboard.server.actors.service.ContextBasedCreator; 22 import org.thingsboard.server.actors.service.ContextBasedCreator;
20 import org.thingsboard.server.common.data.id.DeviceId; 23 import org.thingsboard.server.common.data.id.DeviceId;
21 import org.thingsboard.server.common.data.id.TenantId; 24 import org.thingsboard.server.common.data.id.TenantId;
22 25
23 -public class DeviceActorCreator extends ContextBasedCreator<DeviceActor> {  
24 - private static final long serialVersionUID = 1L; 26 +public class DeviceActorCreator extends ContextBasedCreator {
25 27
26 private final TenantId tenantId; 28 private final TenantId tenantId;
27 private final DeviceId deviceId; 29 private final DeviceId deviceId;
@@ -33,7 +35,13 @@ public class DeviceActorCreator extends ContextBasedCreator<DeviceActor> { @@ -33,7 +35,13 @@ public class DeviceActorCreator extends ContextBasedCreator<DeviceActor> {
33 } 35 }
34 36
35 @Override 37 @Override
36 - public DeviceActor create() { 38 + public TbActorId createActorId() {
  39 + return new TbEntityActorId(deviceId);
  40 + }
  41 +
  42 + @Override
  43 + public TbActor createActor() {
37 return new DeviceActor(context, tenantId, deviceId); 44 return new DeviceActor(context, tenantId, deviceId);
38 } 45 }
  46 +
39 } 47 }
@@ -15,7 +15,6 @@ @@ -15,7 +15,6 @@
15 */ 15 */
16 package org.thingsboard.server.actors.device; 16 package org.thingsboard.server.actors.device;
17 17
18 -import akka.actor.ActorContext;  
19 import com.google.common.util.concurrent.FutureCallback; 18 import com.google.common.util.concurrent.FutureCallback;
20 import com.google.common.util.concurrent.Futures; 19 import com.google.common.util.concurrent.Futures;
21 import com.google.common.util.concurrent.ListenableFuture; 20 import com.google.common.util.concurrent.ListenableFuture;
@@ -27,6 +26,7 @@ import org.thingsboard.rule.engine.api.RpcError; @@ -27,6 +26,7 @@ import org.thingsboard.rule.engine.api.RpcError;
27 import org.thingsboard.rule.engine.api.msg.DeviceAttributesEventNotificationMsg; 26 import org.thingsboard.rule.engine.api.msg.DeviceAttributesEventNotificationMsg;
28 import org.thingsboard.rule.engine.api.msg.DeviceNameOrTypeUpdateMsg; 27 import org.thingsboard.rule.engine.api.msg.DeviceNameOrTypeUpdateMsg;
29 import org.thingsboard.server.actors.ActorSystemContext; 28 import org.thingsboard.server.actors.ActorSystemContext;
  29 +import org.thingsboard.server.actors.TbActorCtx;
30 import org.thingsboard.server.actors.shared.AbstractContextAwareMsgProcessor; 30 import org.thingsboard.server.actors.shared.AbstractContextAwareMsgProcessor;
31 import org.thingsboard.server.common.data.Device; 31 import org.thingsboard.server.common.data.Device;
32 import org.thingsboard.server.common.data.id.DeviceId; 32 import org.thingsboard.server.common.data.id.DeviceId;
@@ -127,7 +127,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { @@ -127,7 +127,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor {
127 } 127 }
128 } 128 }
129 129
130 - void processRpcRequest(ActorContext context, ToDeviceRpcRequestActorMsg msg) { 130 + void processRpcRequest(TbActorCtx context, ToDeviceRpcRequestActorMsg msg) {
131 ToDeviceRpcRequest request = msg.getMsg(); 131 ToDeviceRpcRequest request = msg.getMsg();
132 ToDeviceRpcRequestBody body = request.getBody(); 132 ToDeviceRpcRequestBody body = request.getBody();
133 ToDeviceRpcRequestMsg rpcRequest = ToDeviceRpcRequestMsg.newBuilder().setRequestId( 133 ToDeviceRpcRequestMsg rpcRequest = ToDeviceRpcRequestMsg.newBuilder().setRequestId(
@@ -162,13 +162,13 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { @@ -162,13 +162,13 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor {
162 } 162 }
163 } 163 }
164 164
165 - private void registerPendingRpcRequest(ActorContext context, ToDeviceRpcRequestActorMsg msg, boolean sent, ToDeviceRpcRequestMsg rpcRequest, long timeout) { 165 + private void registerPendingRpcRequest(TbActorCtx context, ToDeviceRpcRequestActorMsg msg, boolean sent, ToDeviceRpcRequestMsg rpcRequest, long timeout) {
166 toDeviceRpcPendingMap.put(rpcRequest.getRequestId(), new ToDeviceRpcRequestMetadata(msg, sent)); 166 toDeviceRpcPendingMap.put(rpcRequest.getRequestId(), new ToDeviceRpcRequestMetadata(msg, sent));
167 DeviceActorServerSideRpcTimeoutMsg timeoutMsg = new DeviceActorServerSideRpcTimeoutMsg(rpcRequest.getRequestId(), timeout); 167 DeviceActorServerSideRpcTimeoutMsg timeoutMsg = new DeviceActorServerSideRpcTimeoutMsg(rpcRequest.getRequestId(), timeout);
168 scheduleMsgWithDelay(context, timeoutMsg, timeoutMsg.getTimeout()); 168 scheduleMsgWithDelay(context, timeoutMsg, timeoutMsg.getTimeout());
169 } 169 }
170 170
171 - void processServerSideRpcTimeout(ActorContext context, DeviceActorServerSideRpcTimeoutMsg msg) { 171 + void processServerSideRpcTimeout(TbActorCtx context, DeviceActorServerSideRpcTimeoutMsg msg) {
172 ToDeviceRpcRequestMetadata requestMd = toDeviceRpcPendingMap.remove(msg.getId()); 172 ToDeviceRpcRequestMetadata requestMd = toDeviceRpcPendingMap.remove(msg.getId());
173 if (requestMd != null) { 173 if (requestMd != null) {
174 log.debug("[{}] RPC request [{}] timeout detected!", deviceId, msg.getId()); 174 log.debug("[{}] RPC request [{}] timeout detected!", deviceId, msg.getId());
@@ -177,7 +177,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { @@ -177,7 +177,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor {
177 } 177 }
178 } 178 }
179 179
180 - private void sendPendingRequests(ActorContext context, UUID sessionId, SessionInfoProto sessionInfo) { 180 + private void sendPendingRequests(TbActorCtx context, UUID sessionId, SessionInfoProto sessionInfo) {
181 SessionType sessionType = getSessionType(sessionId); 181 SessionType sessionType = getSessionType(sessionId);
182 if (!toDeviceRpcPendingMap.isEmpty()) { 182 if (!toDeviceRpcPendingMap.isEmpty()) {
183 log.debug("[{}] Pushing {} pending RPC messages to new async session [{}]", deviceId, toDeviceRpcPendingMap.size(), sessionId); 183 log.debug("[{}] Pushing {} pending RPC messages to new async session [{}]", deviceId, toDeviceRpcPendingMap.size(), sessionId);
@@ -198,7 +198,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { @@ -198,7 +198,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor {
198 sentOneWayIds.forEach(toDeviceRpcPendingMap::remove); 198 sentOneWayIds.forEach(toDeviceRpcPendingMap::remove);
199 } 199 }
200 200
201 - private Consumer<Map.Entry<Integer, ToDeviceRpcRequestMetadata>> processPendingRpc(ActorContext context, UUID sessionId, String nodeId, Set<Integer> sentOneWayIds) { 201 + private Consumer<Map.Entry<Integer, ToDeviceRpcRequestMetadata>> processPendingRpc(TbActorCtx context, UUID sessionId, String nodeId, Set<Integer> sentOneWayIds) {
202 return entry -> { 202 return entry -> {
203 ToDeviceRpcRequest request = entry.getValue().getMsg().getMsg(); 203 ToDeviceRpcRequest request = entry.getValue().getMsg().getMsg();
204 ToDeviceRpcRequestBody body = request.getBody(); 204 ToDeviceRpcRequestBody body = request.getBody();
@@ -212,7 +212,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { @@ -212,7 +212,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor {
212 }; 212 };
213 } 213 }
214 214
215 - void process(ActorContext context, TransportToDeviceActorMsgWrapper wrapper) { 215 + void process(TbActorCtx context, TransportToDeviceActorMsgWrapper wrapper) {
216 TransportToDeviceActorMsg msg = wrapper.getMsg(); 216 TransportToDeviceActorMsg msg = wrapper.getMsg();
217 TbCallback callback = wrapper.getCallback(); 217 TbCallback callback = wrapper.getCallback();
218 if (msg.hasSessionEvent()) { 218 if (msg.hasSessionEvent()) {
@@ -239,7 +239,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { @@ -239,7 +239,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor {
239 callback.onSuccess(); 239 callback.onSuccess();
240 } 240 }
241 241
242 - private void handleClaimDeviceMsg(ActorContext context, SessionInfoProto sessionInfo, TransportProtos.ClaimDeviceMsg msg) { 242 + private void handleClaimDeviceMsg(TbActorCtx context, SessionInfoProto sessionInfo, TransportProtos.ClaimDeviceMsg msg) {
243 DeviceId deviceId = new DeviceId(new UUID(msg.getDeviceIdMSB(), msg.getDeviceIdLSB())); 243 DeviceId deviceId = new DeviceId(new UUID(msg.getDeviceIdMSB(), msg.getDeviceIdLSB()));
244 systemContext.getClaimDevicesService().registerClaimingInfo(tenantId, deviceId, msg.getSecretKey(), msg.getDurationMs()); 244 systemContext.getClaimDevicesService().registerClaimingInfo(tenantId, deviceId, msg.getSecretKey(), msg.getDurationMs());
245 } 245 }
@@ -252,7 +252,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { @@ -252,7 +252,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor {
252 systemContext.getDeviceStateService().onDeviceDisconnect(deviceId); 252 systemContext.getDeviceStateService().onDeviceDisconnect(deviceId);
253 } 253 }
254 254
255 - private void handleGetAttributesRequest(ActorContext context, SessionInfoProto sessionInfo, GetAttributeRequestMsg request) { 255 + private void handleGetAttributesRequest(TbActorCtx context, SessionInfoProto sessionInfo, GetAttributeRequestMsg request) {
256 int requestId = request.getRequestId(); 256 int requestId = request.getRequestId();
257 Futures.addCallback(getAttributesKvEntries(request), new FutureCallback<List<List<AttributeKvEntry>>>() { 257 Futures.addCallback(getAttributesKvEntries(request), new FutureCallback<List<List<AttributeKvEntry>>>() {
258 @Override 258 @Override
@@ -310,7 +310,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { @@ -310,7 +310,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor {
310 return sessions.containsKey(sessionId) ? SessionType.ASYNC : SessionType.SYNC; 310 return sessions.containsKey(sessionId) ? SessionType.ASYNC : SessionType.SYNC;
311 } 311 }
312 312
313 - void processAttributesUpdate(ActorContext context, DeviceAttributesEventNotificationMsg msg) { 313 + void processAttributesUpdate(TbActorCtx context, DeviceAttributesEventNotificationMsg msg) {
314 if (attributeSubscriptions.size() > 0) { 314 if (attributeSubscriptions.size() > 0) {
315 boolean hasNotificationData = false; 315 boolean hasNotificationData = false;
316 AttributeUpdateNotificationMsg.Builder notification = AttributeUpdateNotificationMsg.newBuilder(); 316 AttributeUpdateNotificationMsg.Builder notification = AttributeUpdateNotificationMsg.newBuilder();
@@ -349,7 +349,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { @@ -349,7 +349,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor {
349 } 349 }
350 } 350 }
351 351
352 - private void processRpcResponses(ActorContext context, SessionInfoProto sessionInfo, ToDeviceRpcResponseMsg responseMsg) { 352 + private void processRpcResponses(TbActorCtx context, SessionInfoProto sessionInfo, ToDeviceRpcResponseMsg responseMsg) {
353 UUID sessionId = getSessionId(sessionInfo); 353 UUID sessionId = getSessionId(sessionInfo);
354 log.debug("[{}] Processing rpc command response [{}]", deviceId, sessionId); 354 log.debug("[{}] Processing rpc command response [{}]", deviceId, sessionId);
355 ToDeviceRpcRequestMetadata requestMd = toDeviceRpcPendingMap.remove(responseMsg.getRequestId()); 355 ToDeviceRpcRequestMetadata requestMd = toDeviceRpcPendingMap.remove(responseMsg.getRequestId());
@@ -362,7 +362,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { @@ -362,7 +362,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor {
362 } 362 }
363 } 363 }
364 364
365 - private void processSubscriptionCommands(ActorContext context, SessionInfoProto sessionInfo, SubscribeToAttributeUpdatesMsg subscribeCmd) { 365 + private void processSubscriptionCommands(TbActorCtx context, SessionInfoProto sessionInfo, SubscribeToAttributeUpdatesMsg subscribeCmd) {
366 UUID sessionId = getSessionId(sessionInfo); 366 UUID sessionId = getSessionId(sessionInfo);
367 if (subscribeCmd.getUnsubscribe()) { 367 if (subscribeCmd.getUnsubscribe()) {
368 log.debug("[{}] Canceling attributes subscription for session [{}]", deviceId, sessionId); 368 log.debug("[{}] Canceling attributes subscription for session [{}]", deviceId, sessionId);
@@ -383,7 +383,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { @@ -383,7 +383,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor {
383 return new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB()); 383 return new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB());
384 } 384 }
385 385
386 - private void processSubscriptionCommands(ActorContext context, SessionInfoProto sessionInfo, SubscribeToRPCMsg subscribeCmd) { 386 + private void processSubscriptionCommands(TbActorCtx context, SessionInfoProto sessionInfo, SubscribeToRPCMsg subscribeCmd) {
387 UUID sessionId = getSessionId(sessionInfo); 387 UUID sessionId = getSessionId(sessionInfo);
388 if (subscribeCmd.getUnsubscribe()) { 388 if (subscribeCmd.getUnsubscribe()) {
389 log.debug("[{}] Canceling rpc subscription for session [{}]", deviceId, sessionId); 389 log.debug("[{}] Canceling rpc subscription for session [{}]", deviceId, sessionId);
@@ -433,7 +433,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { @@ -433,7 +433,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor {
433 } 433 }
434 } 434 }
435 435
436 - private void handleSessionActivity(ActorContext context, SessionInfoProto sessionInfoProto, SubscriptionInfoProto subscriptionInfo) { 436 + private void handleSessionActivity(TbActorCtx context, SessionInfoProto sessionInfoProto, SubscriptionInfoProto subscriptionInfo) {
437 UUID sessionId = getSessionId(sessionInfoProto); 437 UUID sessionId = getSessionId(sessionInfoProto);
438 SessionInfoMetaData sessionMD = sessions.computeIfAbsent(sessionId, 438 SessionInfoMetaData sessionMD = sessions.computeIfAbsent(sessionId,
439 id -> new SessionInfoMetaData(new SessionInfo(SessionType.ASYNC, sessionInfoProto.getNodeId()), 0L)); 439 id -> new SessionInfoMetaData(new SessionInfo(SessionType.ASYNC, sessionInfoProto.getNodeId()), 0L));
@@ -612,8 +612,8 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { @@ -612,8 +612,8 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor {
612 .addAllSessions(sessionsList).build().toByteArray()); 612 .addAllSessions(sessionsList).build().toByteArray());
613 } 613 }
614 614
615 - void initSessionTimeout(ActorContext context) {  
616 - schedulePeriodicMsgWithDelay(context, SessionTimeoutCheckMsg.instance(), systemContext.getSessionInactivityTimeout(), systemContext.getSessionInactivityTimeout()); 615 + void initSessionTimeout(TbActorCtx ctx) {
  616 + schedulePeriodicMsgWithDelay(ctx, SessionTimeoutCheckMsg.instance(), systemContext.getSessionInactivityTimeout(), systemContext.getSessionInactivityTimeout());
617 } 617 }
618 618
619 void checkSessionsTimeout() { 619 void checkSessionsTimeout() {
@@ -15,7 +15,6 @@ @@ -15,7 +15,6 @@
15 */ 15 */
16 package org.thingsboard.server.actors.ruleChain; 16 package org.thingsboard.server.actors.ruleChain;
17 17
18 -import akka.actor.ActorRef;  
19 import com.datastax.driver.core.ResultSetFuture; 18 import com.datastax.driver.core.ResultSetFuture;
20 import com.fasterxml.jackson.core.JsonProcessingException; 19 import com.fasterxml.jackson.core.JsonProcessingException;
21 import com.fasterxml.jackson.databind.ObjectMapper; 20 import com.fasterxml.jackson.databind.ObjectMapper;
@@ -30,6 +29,7 @@ import org.thingsboard.rule.engine.api.ScriptEngine; @@ -30,6 +29,7 @@ import org.thingsboard.rule.engine.api.ScriptEngine;
30 import org.thingsboard.rule.engine.api.TbContext; 29 import org.thingsboard.rule.engine.api.TbContext;
31 import org.thingsboard.rule.engine.api.TbRelationTypes; 30 import org.thingsboard.rule.engine.api.TbRelationTypes;
32 import org.thingsboard.server.actors.ActorSystemContext; 31 import org.thingsboard.server.actors.ActorSystemContext;
  32 +import org.thingsboard.server.actors.TbActorRef;
33 import org.thingsboard.server.common.data.Customer; 33 import org.thingsboard.server.common.data.Customer;
34 import org.thingsboard.server.common.data.DataConstants; 34 import org.thingsboard.server.common.data.DataConstants;
35 import org.thingsboard.server.common.data.Device; 35 import org.thingsboard.server.common.data.Device;
@@ -40,6 +40,7 @@ import org.thingsboard.server.common.data.id.RuleChainId; @@ -40,6 +40,7 @@ import org.thingsboard.server.common.data.id.RuleChainId;
40 import org.thingsboard.server.common.data.id.RuleNodeId; 40 import org.thingsboard.server.common.data.id.RuleNodeId;
41 import org.thingsboard.server.common.data.id.TenantId; 41 import org.thingsboard.server.common.data.id.TenantId;
42 import org.thingsboard.server.common.data.rule.RuleNode; 42 import org.thingsboard.server.common.data.rule.RuleNode;
  43 +import org.thingsboard.server.common.msg.TbActorMsg;
43 import org.thingsboard.server.common.msg.TbMsg; 44 import org.thingsboard.server.common.msg.TbMsg;
44 import org.thingsboard.server.common.msg.TbMsgMetaData; 45 import org.thingsboard.server.common.msg.TbMsgMetaData;
45 import org.thingsboard.server.common.msg.queue.ServiceType; 46 import org.thingsboard.server.common.msg.queue.ServiceType;
@@ -64,7 +65,6 @@ import org.thingsboard.server.gen.transport.TransportProtos; @@ -64,7 +65,6 @@ import org.thingsboard.server.gen.transport.TransportProtos;
64 import org.thingsboard.server.queue.TbQueueCallback; 65 import org.thingsboard.server.queue.TbQueueCallback;
65 import org.thingsboard.server.queue.TbQueueMsgMetadata; 66 import org.thingsboard.server.queue.TbQueueMsgMetadata;
66 import org.thingsboard.server.service.script.RuleNodeJsScriptEngine; 67 import org.thingsboard.server.service.script.RuleNodeJsScriptEngine;
67 -import scala.concurrent.duration.Duration;  
68 68
69 import java.util.Collections; 69 import java.util.Collections;
70 import java.util.Set; 70 import java.util.Set;
@@ -106,7 +106,7 @@ class DefaultTbContext implements TbContext { @@ -106,7 +106,7 @@ class DefaultTbContext implements TbContext {
106 if (nodeCtx.getSelf().isDebugMode()) { 106 if (nodeCtx.getSelf().isDebugMode()) {
107 relationTypes.forEach(relationType -> mainCtx.persistDebugOutput(nodeCtx.getTenantId(), nodeCtx.getSelf().getId(), msg, relationType, th)); 107 relationTypes.forEach(relationType -> mainCtx.persistDebugOutput(nodeCtx.getTenantId(), nodeCtx.getSelf().getId(), msg, relationType, th));
108 } 108 }
109 - nodeCtx.getChainActor().tell(new RuleNodeToRuleChainTellNextMsg(nodeCtx.getSelf().getId(), relationTypes, msg, th != null ? th.getMessage() : null), nodeCtx.getSelfActor()); 109 + nodeCtx.getChainActor().tell(new RuleNodeToRuleChainTellNextMsg(nodeCtx.getSelf().getId(), relationTypes, msg, th != null ? th.getMessage() : null));
110 } 110 }
111 111
112 @Override 112 @Override
@@ -132,7 +132,7 @@ class DefaultTbContext implements TbContext { @@ -132,7 +132,7 @@ class DefaultTbContext implements TbContext {
132 .setTenantIdMSB(getTenantId().getId().getMostSignificantBits()) 132 .setTenantIdMSB(getTenantId().getId().getMostSignificantBits())
133 .setTenantIdLSB(getTenantId().getId().getLeastSignificantBits()) 133 .setTenantIdLSB(getTenantId().getId().getLeastSignificantBits())
134 .setTbMsg(TbMsg.toByteString(tbMsg)).build(); 134 .setTbMsg(TbMsg.toByteString(tbMsg)).build();
135 - mainCtx.getClusterService().pushMsgToRuleEngine(tpi, tbMsg.getId(), msg, new SimpleTbQueueCallback(onSuccess, onFailure)); 135 + mainCtx.getClusterService().pushMsgToRuleEngine(tpi, tbMsg.getId(), msg, new SimpleTbQueueCallback(onSuccess, onFailure));
136 } 136 }
137 137
138 @Override 138 @Override
@@ -189,7 +189,7 @@ class DefaultTbContext implements TbContext { @@ -189,7 +189,7 @@ class DefaultTbContext implements TbContext {
189 if (failureMessage != null) { 189 if (failureMessage != null) {
190 msg.setFailureMessage(failureMessage); 190 msg.setFailureMessage(failureMessage);
191 } 191 }
192 - mainCtx.getClusterService().pushMsgToRuleEngine(tpi, tbMsg.getId(), msg.build(), new SimpleTbQueueCallback(onSuccess, onFailure)); 192 + mainCtx.getClusterService().pushMsgToRuleEngine(tpi, tbMsg.getId(), msg.build(), new SimpleTbQueueCallback(onSuccess, onFailure));
193 } 193 }
194 194
195 @Override 195 @Override
@@ -205,8 +205,8 @@ class DefaultTbContext implements TbContext { @@ -205,8 +205,8 @@ class DefaultTbContext implements TbContext {
205 return mainCtx.resolve(ServiceType.TB_RULE_ENGINE, getTenantId(), entityId).isMyPartition(); 205 return mainCtx.resolve(ServiceType.TB_RULE_ENGINE, getTenantId(), entityId).isMyPartition();
206 } 206 }
207 207
208 - private void scheduleMsgWithDelay(Object msg, long delayInMs, ActorRef target) {  
209 - mainCtx.getScheduler().scheduleOnce(Duration.create(delayInMs, TimeUnit.MILLISECONDS), target, msg, mainCtx.getActorSystem().dispatcher(), nodeCtx.getSelfActor()); 208 + private void scheduleMsgWithDelay(TbActorMsg msg, long delayInMs, TbActorRef target) {
  209 + mainCtx.scheduleMsgWithDelay(target, msg, delayInMs);
210 } 210 }
211 211
212 @Override 212 @Override
@@ -215,7 +215,7 @@ class DefaultTbContext implements TbContext { @@ -215,7 +215,7 @@ class DefaultTbContext implements TbContext {
215 mainCtx.persistDebugOutput(nodeCtx.getTenantId(), nodeCtx.getSelf().getId(), msg, TbRelationTypes.FAILURE, th); 215 mainCtx.persistDebugOutput(nodeCtx.getTenantId(), nodeCtx.getSelf().getId(), msg, TbRelationTypes.FAILURE, th);
216 } 216 }
217 nodeCtx.getChainActor().tell(new RuleNodeToRuleChainTellNextMsg(nodeCtx.getSelf().getId(), Collections.singleton(TbRelationTypes.FAILURE), 217 nodeCtx.getChainActor().tell(new RuleNodeToRuleChainTellNextMsg(nodeCtx.getSelf().getId(), Collections.singleton(TbRelationTypes.FAILURE),
218 - msg, th != null ? th.getMessage() : null), nodeCtx.getSelfActor()); 218 + msg, th != null ? th.getMessage() : null));
219 } 219 }
220 220
221 public void updateSelf(RuleNode self) { 221 public void updateSelf(RuleNode self) {
@@ -223,8 +223,8 @@ class DefaultTbContext implements TbContext { @@ -223,8 +223,8 @@ class DefaultTbContext implements TbContext {
223 } 223 }
224 224
225 @Override 225 @Override
226 - public TbMsg newMsg(String type, EntityId originator, TbMsgMetaData metaData, String data) {  
227 - return TbMsg.newMsg(type, originator, metaData, data, nodeCtx.getSelf().getRuleChainId(), nodeCtx.getSelf().getId()); 226 + public TbMsg newMsg(String queueName, String type, EntityId originator, TbMsgMetaData metaData, String data) {
  227 + return TbMsg.newMsg(queueName, type, originator, metaData, data, nodeCtx.getSelf().getRuleChainId(), nodeCtx.getSelf().getId());
228 } 228 }
229 229
230 @Override 230 @Override
@@ -15,9 +15,11 @@ @@ -15,9 +15,11 @@
15 */ 15 */
16 package org.thingsboard.server.actors.ruleChain; 16 package org.thingsboard.server.actors.ruleChain;
17 17
18 -import akka.actor.OneForOneStrategy;  
19 -import akka.actor.SupervisorStrategy;  
20 import org.thingsboard.server.actors.ActorSystemContext; 18 import org.thingsboard.server.actors.ActorSystemContext;
  19 +import org.thingsboard.server.actors.TbActor;
  20 +import org.thingsboard.server.actors.TbActorCtx;
  21 +import org.thingsboard.server.actors.TbActorId;
  22 +import org.thingsboard.server.actors.TbEntityActorId;
21 import org.thingsboard.server.actors.service.ComponentActor; 23 import org.thingsboard.server.actors.service.ComponentActor;
22 import org.thingsboard.server.actors.service.ContextBasedCreator; 24 import org.thingsboard.server.actors.service.ContextBasedCreator;
23 import org.thingsboard.server.common.data.id.RuleChainId; 25 import org.thingsboard.server.common.data.id.RuleChainId;
@@ -27,18 +29,24 @@ import org.thingsboard.server.common.msg.TbActorMsg; @@ -27,18 +29,24 @@ import org.thingsboard.server.common.msg.TbActorMsg;
27 import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; 29 import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg;
28 import org.thingsboard.server.common.msg.queue.PartitionChangeMsg; 30 import org.thingsboard.server.common.msg.queue.PartitionChangeMsg;
29 import org.thingsboard.server.common.msg.queue.QueueToRuleEngineMsg; 31 import org.thingsboard.server.common.msg.queue.QueueToRuleEngineMsg;
30 -import scala.concurrent.duration.Duration;  
31 32
32 public class RuleChainActor extends ComponentActor<RuleChainId, RuleChainActorMessageProcessor> { 33 public class RuleChainActor extends ComponentActor<RuleChainId, RuleChainActorMessageProcessor> {
33 34
  35 + private final RuleChain ruleChain;
  36 +
34 private RuleChainActor(ActorSystemContext systemContext, TenantId tenantId, RuleChain ruleChain) { 37 private RuleChainActor(ActorSystemContext systemContext, TenantId tenantId, RuleChain ruleChain) {
35 super(systemContext, tenantId, ruleChain.getId()); 38 super(systemContext, tenantId, ruleChain.getId());
36 - setProcessor(new RuleChainActorMessageProcessor(tenantId, ruleChain, systemContext,  
37 - context().parent(), context().self())); 39 + this.ruleChain = ruleChain;
38 } 40 }
39 41
40 @Override 42 @Override
41 - protected boolean process(TbActorMsg msg) { 43 + protected RuleChainActorMessageProcessor createProcessor(TbActorCtx ctx) {
  44 + return new RuleChainActorMessageProcessor(tenantId, ruleChain, systemContext,
  45 + ctx.getParentRef(), ctx);
  46 + }
  47 +
  48 + @Override
  49 + protected boolean doProcess(TbActorMsg msg) {
42 switch (msg.getMsgType()) { 50 switch (msg.getMsgType()) {
43 case COMPONENT_LIFE_CYCLE_MSG: 51 case COMPONENT_LIFE_CYCLE_MSG:
44 onComponentLifecycleMsg((ComponentLifecycleMsg) msg); 52 onComponentLifecycleMsg((ComponentLifecycleMsg) msg);
@@ -64,7 +72,7 @@ public class RuleChainActor extends ComponentActor<RuleChainId, RuleChainActorMe @@ -64,7 +72,7 @@ public class RuleChainActor extends ComponentActor<RuleChainId, RuleChainActorMe
64 return true; 72 return true;
65 } 73 }
66 74
67 - public static class ActorCreator extends ContextBasedCreator<RuleChainActor> { 75 + public static class ActorCreator extends ContextBasedCreator {
68 private static final long serialVersionUID = 1L; 76 private static final long serialVersionUID = 1L;
69 77
70 private final TenantId tenantId; 78 private final TenantId tenantId;
@@ -77,7 +85,12 @@ public class RuleChainActor extends ComponentActor<RuleChainId, RuleChainActorMe @@ -77,7 +85,12 @@ public class RuleChainActor extends ComponentActor<RuleChainId, RuleChainActorMe
77 } 85 }
78 86
79 @Override 87 @Override
80 - public RuleChainActor create() { 88 + public TbActorId createActorId() {
  89 + return new TbEntityActorId(ruleChain.getId());
  90 + }
  91 +
  92 + @Override
  93 + public TbActor createActor() {
81 return new RuleChainActor(context, tenantId, ruleChain); 94 return new RuleChainActor(context, tenantId, ruleChain);
82 } 95 }
83 } 96 }
@@ -87,13 +100,4 @@ public class RuleChainActor extends ComponentActor<RuleChainId, RuleChainActorMe @@ -87,13 +100,4 @@ public class RuleChainActor extends ComponentActor<RuleChainId, RuleChainActorMe
87 return systemContext.getRuleChainErrorPersistFrequency(); 100 return systemContext.getRuleChainErrorPersistFrequency();
88 } 101 }
89 102
90 - @Override  
91 - public SupervisorStrategy supervisorStrategy() {  
92 - return strategy;  
93 - }  
94 -  
95 - private final SupervisorStrategy strategy = new OneForOneStrategy(3, Duration.create("1 minute"), t -> {  
96 - logAndPersist("Unknown Failure", ActorSystemContext.toException(t));  
97 - return SupervisorStrategy.resume();  
98 - });  
99 } 103 }
@@ -15,12 +15,12 @@ @@ -15,12 +15,12 @@
15 */ 15 */
16 package org.thingsboard.server.actors.ruleChain; 16 package org.thingsboard.server.actors.ruleChain;
17 17
18 -import akka.actor.ActorContext;  
19 -import akka.actor.ActorRef;  
20 -import akka.actor.Props;  
21 import lombok.extern.slf4j.Slf4j; 18 import lombok.extern.slf4j.Slf4j;
22 import org.thingsboard.rule.engine.api.TbRelationTypes; 19 import org.thingsboard.rule.engine.api.TbRelationTypes;
23 import org.thingsboard.server.actors.ActorSystemContext; 20 import org.thingsboard.server.actors.ActorSystemContext;
  21 +import org.thingsboard.server.actors.TbActorCtx;
  22 +import org.thingsboard.server.actors.TbActorRef;
  23 +import org.thingsboard.server.actors.TbEntityActorId;
24 import org.thingsboard.server.actors.service.DefaultActorService; 24 import org.thingsboard.server.actors.service.DefaultActorService;
25 import org.thingsboard.server.actors.shared.ComponentMsgProcessor; 25 import org.thingsboard.server.actors.shared.ComponentMsgProcessor;
26 import org.thingsboard.server.common.data.EntityType; 26 import org.thingsboard.server.common.data.EntityType;
@@ -64,20 +64,21 @@ import java.util.stream.Collectors; @@ -64,20 +64,21 @@ import java.util.stream.Collectors;
64 @Slf4j 64 @Slf4j
65 public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleChainId> { 65 public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleChainId> {
66 66
67 - private final ActorRef parent;  
68 - private final ActorRef self; 67 + private final TbActorRef parent;
  68 + private final TbActorRef self;
69 private final Map<RuleNodeId, RuleNodeCtx> nodeActors; 69 private final Map<RuleNodeId, RuleNodeCtx> nodeActors;
70 private final Map<RuleNodeId, List<RuleNodeRelation>> nodeRoutes; 70 private final Map<RuleNodeId, List<RuleNodeRelation>> nodeRoutes;
71 private final RuleChainService service; 71 private final RuleChainService service;
72 private final TbClusterService clusterService; 72 private final TbClusterService clusterService;
73 private final EdgeService edgeService; 73 private final EdgeService edgeService;
74 private String ruleChainName; 74 private String ruleChainName;
  75 +
75 private RuleNodeId firstId; 76 private RuleNodeId firstId;
76 private RuleNodeCtx firstNode; 77 private RuleNodeCtx firstNode;
77 private boolean started; 78 private boolean started;
78 79
79 RuleChainActorMessageProcessor(TenantId tenantId, RuleChain ruleChain, ActorSystemContext systemContext 80 RuleChainActorMessageProcessor(TenantId tenantId, RuleChain ruleChain, ActorSystemContext systemContext
80 - , ActorRef parent, ActorRef self) { 81 + , TbActorRef parent, TbActorRef self) {
81 super(systemContext, tenantId, ruleChain.getId()); 82 super(systemContext, tenantId, ruleChain.getId());
82 this.ruleChainName = ruleChain.getName(); 83 this.ruleChainName = ruleChain.getName();
83 this.parent = parent; 84 this.parent = parent;
@@ -95,7 +96,7 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh @@ -95,7 +96,7 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh
95 } 96 }
96 97
97 @Override 98 @Override
98 - public void start(ActorContext context) { 99 + public void start(TbActorCtx context) {
99 if (!started) { 100 if (!started) {
100 RuleChain ruleChain = service.findRuleChainById(tenantId, entityId); 101 RuleChain ruleChain = service.findRuleChainById(tenantId, entityId);
101 if (ruleChain != null) { 102 if (ruleChain != null) {
@@ -105,7 +106,7 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh @@ -105,7 +106,7 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh
105 // Creating and starting the actors; 106 // Creating and starting the actors;
106 for (RuleNode ruleNode : ruleNodeList) { 107 for (RuleNode ruleNode : ruleNodeList) {
107 log.trace("[{}][{}] Creating rule node [{}]: {}", entityId, ruleNode.getId(), ruleNode.getName(), ruleNode); 108 log.trace("[{}][{}] Creating rule node [{}]: {}", entityId, ruleNode.getId(), ruleNode.getName(), ruleNode);
108 - ActorRef ruleNodeActor = createRuleNodeActor(context, ruleNode); 109 + TbActorRef ruleNodeActor = createRuleNodeActor(context, ruleNode);
109 nodeActors.put(ruleNode.getId(), new RuleNodeCtx(tenantId, self, ruleNodeActor, ruleNode)); 110 nodeActors.put(ruleNode.getId(), new RuleNodeCtx(tenantId, self, ruleNodeActor, ruleNode));
110 } 111 }
111 initRoutes(ruleChain, ruleNodeList); 112 initRoutes(ruleChain, ruleNodeList);
@@ -118,7 +119,7 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh @@ -118,7 +119,7 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh
118 } 119 }
119 120
120 @Override 121 @Override
121 - public void onUpdate(ActorContext context) { 122 + public void onUpdate(TbActorCtx context) {
122 RuleChain ruleChain = service.findRuleChainById(tenantId, entityId); 123 RuleChain ruleChain = service.findRuleChainById(tenantId, entityId);
123 if (ruleChain != null) { 124 if (ruleChain != null) {
124 if (ruleChain.getType().equals(RuleChainType.CORE)) { 125 if (ruleChain.getType().equals(RuleChainType.CORE)) {
@@ -129,22 +130,22 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh @@ -129,22 +130,22 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh
129 RuleNodeCtx existing = nodeActors.get(ruleNode.getId()); 130 RuleNodeCtx existing = nodeActors.get(ruleNode.getId());
130 if (existing == null) { 131 if (existing == null) {
131 log.trace("[{}][{}] Creating rule node [{}]: {}", entityId, ruleNode.getId(), ruleNode.getName(), ruleNode); 132 log.trace("[{}][{}] Creating rule node [{}]: {}", entityId, ruleNode.getId(), ruleNode.getName(), ruleNode);
132 - ActorRef ruleNodeActor = createRuleNodeActor(context, ruleNode); 133 + TbActorRef ruleNodeActor = createRuleNodeActor(context, ruleNode);
133 nodeActors.put(ruleNode.getId(), new RuleNodeCtx(tenantId, self, ruleNodeActor, ruleNode)); 134 nodeActors.put(ruleNode.getId(), new RuleNodeCtx(tenantId, self, ruleNodeActor, ruleNode));
134 } else { 135 } else {
135 log.trace("[{}][{}] Updating rule node [{}]: {}", entityId, ruleNode.getId(), ruleNode.getName(), ruleNode); 136 log.trace("[{}][{}] Updating rule node [{}]: {}", entityId, ruleNode.getId(), ruleNode.getName(), ruleNode);
136 existing.setSelf(ruleNode); 137 existing.setSelf(ruleNode);
137 - existing.getSelfActor().tell(new ComponentLifecycleMsg(tenantId, existing.getSelf().getId(), ComponentLifecycleEvent.UPDATED), self); 138 + existing.getSelfActor().tellWithHighPriority(new ComponentLifecycleMsg(tenantId, existing.getSelf().getId(), ComponentLifecycleEvent.UPDATED));
138 } 139 }
139 } 140 }
140 141
141 - Set<RuleNodeId> existingNodes = ruleNodeList.stream().map(RuleNode::getId).collect(Collectors.toSet());  
142 - List<RuleNodeId> removedRules = nodeActors.keySet().stream().filter(node -> !existingNodes.contains(node)).collect(Collectors.toList());  
143 - removedRules.forEach(ruleNodeId -> {  
144 - log.trace("[{}][{}] Removing rule node [{}]", tenantId, entityId, ruleNodeId);  
145 - RuleNodeCtx removed = nodeActors.remove(ruleNodeId);  
146 - removed.getSelfActor().tell(new ComponentLifecycleMsg(tenantId, removed.getSelf().getId(), ComponentLifecycleEvent.DELETED), self);  
147 - }); 142 + Set<RuleNodeId> existingNodes = ruleNodeList.stream().map(RuleNode::getId).collect(Collectors.toSet());
  143 + List<RuleNodeId> removedRules = nodeActors.keySet().stream().filter(node -> !existingNodes.contains(node)).collect(Collectors.toList());
  144 + removedRules.forEach(ruleNodeId -> {
  145 + log.trace("[{}][{}] Removing rule node [{}]", tenantId, entityId, ruleNodeId);
  146 + RuleNodeCtx removed = nodeActors.remove(ruleNodeId);
  147 + removed.getSelfActor().tellWithHighPriority(new ComponentLifecycleMsg(tenantId, removed.getSelf().getId(), ComponentLifecycleEvent.DELETED));
  148 + });
148 149
149 initRoutes(ruleChain, ruleNodeList); 150 initRoutes(ruleChain, ruleNodeList);
150 } else if (ruleChain.getType().equals(RuleChainType.EDGE)) { 151 } else if (ruleChain.getType().equals(RuleChainType.EDGE)) {
@@ -154,26 +155,23 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh @@ -154,26 +155,23 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh
154 } 155 }
155 156
156 @Override 157 @Override
157 - public void stop(ActorContext context) { 158 + public void stop(TbActorCtx ctx) {
158 log.trace("[{}][{}] Stopping rule chain with {} nodes", tenantId, entityId, nodeActors.size()); 159 log.trace("[{}][{}] Stopping rule chain with {} nodes", tenantId, entityId, nodeActors.size());
159 - nodeActors.values().stream().map(RuleNodeCtx::getSelfActor).forEach(context::stop); 160 + nodeActors.values().stream().map(RuleNodeCtx::getSelfActor).map(TbActorRef::getActorId).forEach(ctx::stop);
160 nodeActors.clear(); 161 nodeActors.clear();
161 nodeRoutes.clear(); 162 nodeRoutes.clear();
162 - context.stop(self);  
163 started = false; 163 started = false;
164 } 164 }
165 165
166 @Override 166 @Override
167 public void onPartitionChangeMsg(PartitionChangeMsg msg) { 167 public void onPartitionChangeMsg(PartitionChangeMsg msg) {
168 - nodeActors.values().stream().map(RuleNodeCtx::getSelfActor).forEach(actorRef -> actorRef.tell(msg, self)); 168 + nodeActors.values().stream().map(RuleNodeCtx::getSelfActor).forEach(actorRef -> actorRef.tellWithHighPriority(msg));
169 } 169 }
170 170
171 - private ActorRef createRuleNodeActor(ActorContext context, RuleNode ruleNode) {  
172 - String dispatcherName = tenantId.getId().equals(EntityId.NULL_UUID) ?  
173 - DefaultActorService.SYSTEM_RULE_DISPATCHER_NAME : DefaultActorService.TENANT_RULE_DISPATCHER_NAME;  
174 - return context.actorOf(  
175 - Props.create(new RuleNodeActor.ActorCreator(systemContext, tenantId, entityId, ruleNode.getName(), ruleNode.getId()))  
176 - .withDispatcher(dispatcherName), ruleNode.getId().toString()); 171 + private TbActorRef createRuleNodeActor(TbActorCtx ctx, RuleNode ruleNode) {
  172 + return ctx.getOrCreateChildActor(new TbEntityActorId(ruleNode.getId()),
  173 + () -> DefaultActorService.RULE_DISPATCHER_NAME,
  174 + () -> new RuleNodeActor.ActorCreator(systemContext, tenantId, entityId, ruleNode.getName(), ruleNode.getId()));
177 } 175 }
178 176
179 private void initRoutes(RuleChain ruleChain, List<RuleNode> ruleNodeList) { 177 private void initRoutes(RuleChain ruleChain, List<RuleNode> ruleNodeList) {
@@ -256,7 +254,7 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh @@ -256,7 +254,7 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh
256 try { 254 try {
257 checkActive(msg); 255 checkActive(msg);
258 EntityId entityId = msg.getOriginator(); 256 EntityId entityId = msg.getOriginator();
259 - TopicPartitionInfo tpi = systemContext.resolve(ServiceType.TB_RULE_ENGINE, tenantId, entityId); 257 + TopicPartitionInfo tpi = systemContext.resolve(ServiceType.TB_RULE_ENGINE, msg.getQueueName(), tenantId, entityId);
260 List<RuleNodeRelation> relations = nodeRoutes.get(originatorNodeId).stream() 258 List<RuleNodeRelation> relations = nodeRoutes.get(originatorNodeId).stream()
261 .filter(r -> contains(relationTypes, r.getType())) 259 .filter(r -> contains(relationTypes, r.getType()))
262 .collect(Collectors.toList()); 260 .collect(Collectors.toList());
@@ -312,7 +310,7 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh @@ -312,7 +310,7 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh
312 pushMsgToNode(nodeActors.get(new RuleNodeId(target.getId())), msg, fromRelationType); 310 pushMsgToNode(nodeActors.get(new RuleNodeId(target.getId())), msg, fromRelationType);
313 break; 311 break;
314 case RULE_CHAIN: 312 case RULE_CHAIN:
315 - parent.tell(new RuleChainToRuleChainMsg(new RuleChainId(target.getId()), entityId, msg, fromRelationType), self); 313 + parent.tell(new RuleChainToRuleChainMsg(new RuleChainId(target.getId()), entityId, msg, fromRelationType));
316 break; 314 break;
317 } 315 }
318 } else { 316 } else {
@@ -343,7 +341,7 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh @@ -343,7 +341,7 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh
343 341
344 private void pushMsgToNode(RuleNodeCtx nodeCtx, TbMsg msg, String fromRelationType) { 342 private void pushMsgToNode(RuleNodeCtx nodeCtx, TbMsg msg, String fromRelationType) {
345 if (nodeCtx != null) { 343 if (nodeCtx != null) {
346 - nodeCtx.getSelfActor().tell(new RuleChainToRuleNodeMsg(new DefaultTbContext(systemContext, nodeCtx), msg, fromRelationType), self); 344 + nodeCtx.getSelfActor().tell(new RuleChainToRuleNodeMsg(new DefaultTbContext(systemContext, nodeCtx), msg, fromRelationType));
347 } else { 345 } else {
348 log.error("[{}][{}] RuleNodeCtx is empty", entityId, ruleChainName); 346 log.error("[{}][{}] RuleNodeCtx is empty", entityId, ruleChainName);
349 msg.getCallback().onFailure(new RuleEngineException("Rule Node CTX is empty")); 347 msg.getCallback().onFailure(new RuleEngineException("Rule Node CTX is empty"));
@@ -15,21 +15,22 @@ @@ -15,21 +15,22 @@
15 */ 15 */
16 package org.thingsboard.server.actors.ruleChain; 16 package org.thingsboard.server.actors.ruleChain;
17 17
18 -import akka.actor.ActorContext;  
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; 18 import lombok.Getter;
  19 +import lombok.extern.slf4j.Slf4j;
24 import org.thingsboard.server.actors.ActorSystemContext; 20 import org.thingsboard.server.actors.ActorSystemContext;
  21 +import org.thingsboard.server.actors.TbActorRef;
  22 +import org.thingsboard.server.actors.TbEntityActorId;
  23 +import org.thingsboard.server.actors.TbEntityTypeActorIdPredicate;
25 import org.thingsboard.server.actors.service.ContextAwareActor; 24 import org.thingsboard.server.actors.service.ContextAwareActor;
26 import org.thingsboard.server.actors.service.DefaultActorService; 25 import org.thingsboard.server.actors.service.DefaultActorService;
  26 +import org.thingsboard.server.actors.tenant.TenantActor;
27 import org.thingsboard.server.common.data.EntityType; 27 import org.thingsboard.server.common.data.EntityType;
28 import org.thingsboard.server.common.data.id.EntityId; 28 import org.thingsboard.server.common.data.id.EntityId;
29 import org.thingsboard.server.common.data.id.RuleChainId; 29 import org.thingsboard.server.common.data.id.RuleChainId;
30 import org.thingsboard.server.common.data.id.TenantId; 30 import org.thingsboard.server.common.data.id.TenantId;
31 import org.thingsboard.server.common.data.page.PageDataIterable; 31 import org.thingsboard.server.common.data.page.PageDataIterable;
32 import org.thingsboard.server.common.data.rule.RuleChain; 32 import org.thingsboard.server.common.data.rule.RuleChain;
  33 +import org.thingsboard.server.common.msg.TbActorMsg;
33 import org.thingsboard.server.common.data.rule.RuleChainType; 34 import org.thingsboard.server.common.data.rule.RuleChainType;
34 import org.thingsboard.server.dao.rule.RuleChainService; 35 import org.thingsboard.server.dao.rule.RuleChainService;
35 36
@@ -38,20 +39,19 @@ import java.util.function.Function; @@ -38,20 +39,19 @@ import java.util.function.Function;
38 /** 39 /**
39 * Created by ashvayka on 15.03.18. 40 * Created by ashvayka on 15.03.18.
40 */ 41 */
  42 +@Slf4j
41 public abstract class RuleChainManagerActor extends ContextAwareActor { 43 public abstract class RuleChainManagerActor extends ContextAwareActor {
42 44
43 protected final TenantId tenantId; 45 protected final TenantId tenantId;
44 private final RuleChainService ruleChainService; 46 private final RuleChainService ruleChainService;
45 - private final BiMap<RuleChainId, ActorRef> actors;  
46 @Getter 47 @Getter
47 protected RuleChain rootChain; 48 protected RuleChain rootChain;
48 @Getter 49 @Getter
49 - protected ActorRef rootChainActor; 50 + protected TbActorRef rootChainActor;
50 51
51 public RuleChainManagerActor(ActorSystemContext systemContext, TenantId tenantId) { 52 public RuleChainManagerActor(ActorSystemContext systemContext, TenantId tenantId) {
52 super(systemContext); 53 super(systemContext);
53 this.tenantId = tenantId; 54 this.tenantId = tenantId;
54 - this.actors = HashBiMap.create();  
55 this.ruleChainService = systemContext.getRuleChainService(); 55 this.ruleChainService = systemContext.getRuleChainService();
56 } 56 }
57 57
@@ -59,46 +59,41 @@ public abstract class RuleChainManagerActor extends ContextAwareActor { @@ -59,46 +59,41 @@ public abstract class RuleChainManagerActor extends ContextAwareActor {
59 for (RuleChain ruleChain : new PageDataIterable<>(link -> ruleChainService.findTenantRuleChainsByType(tenantId, RuleChainType.CORE, link), ContextAwareActor.ENTITY_PACK_LIMIT)) { 59 for (RuleChain ruleChain : new PageDataIterable<>(link -> ruleChainService.findTenantRuleChainsByType(tenantId, RuleChainType.CORE, link), ContextAwareActor.ENTITY_PACK_LIMIT)) {
60 RuleChainId ruleChainId = ruleChain.getId(); 60 RuleChainId ruleChainId = ruleChain.getId();
61 log.debug("[{}|{}] Creating rule chain actor", ruleChainId.getEntityType(), ruleChain.getId()); 61 log.debug("[{}|{}] Creating rule chain actor", ruleChainId.getEntityType(), ruleChain.getId());
62 - //TODO: remove this cast making UUIDBased subclass of EntityId an interface and vice versa.  
63 - ActorRef actorRef = getOrCreateActor(this.context(), ruleChainId, id -> ruleChain); 62 + TbActorRef actorRef = getOrCreateActor(ruleChainId, id -> ruleChain);
64 visit(ruleChain, actorRef); 63 visit(ruleChain, actorRef);
65 log.debug("[{}|{}] Rule Chain actor created.", ruleChainId.getEntityType(), ruleChainId.getId()); 64 log.debug("[{}|{}] Rule Chain actor created.", ruleChainId.getEntityType(), ruleChainId.getId());
66 } 65 }
67 } 66 }
68 67
69 - protected void visit(RuleChain entity, ActorRef actorRef) { 68 + protected void visit(RuleChain entity, TbActorRef actorRef) {
70 if (entity != null && entity.isRoot() && entity.getType().equals(RuleChainType.CORE)) { 69 if (entity != null && entity.isRoot() && entity.getType().equals(RuleChainType.CORE)) {
71 rootChain = entity; 70 rootChain = entity;
72 rootChainActor = actorRef; 71 rootChainActor = actorRef;
73 } 72 }
74 } 73 }
75 74
76 - public ActorRef getOrCreateActor(akka.actor.ActorContext context, RuleChainId ruleChainId) {  
77 - return getOrCreateActor(context, ruleChainId, eId -> ruleChainService.findRuleChainById(TenantId.SYS_TENANT_ID, eId)); 75 + protected TbActorRef getOrCreateActor(RuleChainId ruleChainId) {
  76 + return getOrCreateActor(ruleChainId, eId -> ruleChainService.findRuleChainById(TenantId.SYS_TENANT_ID, eId));
78 } 77 }
79 78
80 - public ActorRef getOrCreateActor(akka.actor.ActorContext context, RuleChainId ruleChainId, Function<RuleChainId, RuleChain> provider) {  
81 - return actors.computeIfAbsent(ruleChainId, eId -> {  
82 - RuleChain ruleChain = provider.apply(eId);  
83 - return context.actorOf(Props.create(new RuleChainActor.ActorCreator(systemContext, tenantId, ruleChain))  
84 - .withDispatcher(DefaultActorService.TENANT_RULE_DISPATCHER_NAME), eId.toString());  
85 - }); 79 + protected TbActorRef getOrCreateActor(RuleChainId ruleChainId, Function<RuleChainId, RuleChain> provider) {
  80 + return ctx.getOrCreateChildActor(new TbEntityActorId(ruleChainId),
  81 + () -> DefaultActorService.RULE_DISPATCHER_NAME,
  82 + () -> {
  83 + RuleChain ruleChain = provider.apply(ruleChainId);
  84 + return new RuleChainActor.ActorCreator(systemContext, tenantId, ruleChain);
  85 + });
86 } 86 }
87 87
88 - protected ActorRef getEntityActorRef(EntityId entityId) {  
89 - ActorRef target = null; 88 + protected TbActorRef getEntityActorRef(EntityId entityId) {
  89 + TbActorRef target = null;
90 if (entityId.getEntityType() == EntityType.RULE_CHAIN) { 90 if (entityId.getEntityType() == EntityType.RULE_CHAIN) {
91 - target = getOrCreateActor(this.context(), (RuleChainId) entityId); 91 + target = getOrCreateActor((RuleChainId) entityId);
92 } 92 }
93 return target; 93 return target;
94 } 94 }
95 95
96 - protected void broadcast(Object msg) {  
97 - actors.values().forEach(actorRef -> actorRef.tell(msg, ActorRef.noSender())); 96 + protected void broadcast(TbActorMsg msg) {
  97 + ctx.broadcastToChildren(msg, new TbEntityTypeActorIdPredicate(EntityType.RULE_CHAIN));
98 } 98 }
99 -  
100 - public ActorRef get(RuleChainId id) {  
101 - return actors.get(id);  
102 - }  
103 -  
104 } 99 }
@@ -15,31 +15,43 @@ @@ -15,31 +15,43 @@
15 */ 15 */
16 package org.thingsboard.server.actors.ruleChain; 16 package org.thingsboard.server.actors.ruleChain;
17 17
  18 +import lombok.extern.slf4j.Slf4j;
18 import org.thingsboard.server.actors.ActorSystemContext; 19 import org.thingsboard.server.actors.ActorSystemContext;
  20 +import org.thingsboard.server.actors.TbActor;
  21 +import org.thingsboard.server.actors.TbActorCtx;
  22 +import org.thingsboard.server.actors.TbActorId;
  23 +import org.thingsboard.server.actors.TbEntityActorId;
19 import org.thingsboard.server.actors.service.ComponentActor; 24 import org.thingsboard.server.actors.service.ComponentActor;
20 import org.thingsboard.server.actors.service.ContextBasedCreator; 25 import org.thingsboard.server.actors.service.ContextBasedCreator;
21 import org.thingsboard.server.common.data.id.RuleChainId; 26 import org.thingsboard.server.common.data.id.RuleChainId;
22 import org.thingsboard.server.common.data.id.RuleNodeId; 27 import org.thingsboard.server.common.data.id.RuleNodeId;
23 import org.thingsboard.server.common.data.id.TenantId; 28 import org.thingsboard.server.common.data.id.TenantId;
  29 +import org.thingsboard.server.common.data.rule.RuleChain;
24 import org.thingsboard.server.common.msg.TbActorMsg; 30 import org.thingsboard.server.common.msg.TbActorMsg;
25 import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; 31 import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg;
26 import org.thingsboard.server.common.msg.queue.PartitionChangeMsg; 32 import org.thingsboard.server.common.msg.queue.PartitionChangeMsg;
27 33
  34 +@Slf4j
28 public class RuleNodeActor extends ComponentActor<RuleNodeId, RuleNodeActorMessageProcessor> { 35 public class RuleNodeActor extends ComponentActor<RuleNodeId, RuleNodeActorMessageProcessor> {
29 36
30 private final String ruleChainName; 37 private final String ruleChainName;
31 private final RuleChainId ruleChainId; 38 private final RuleChainId ruleChainId;
  39 + private final RuleNodeId ruleNodeId;
32 40
33 private RuleNodeActor(ActorSystemContext systemContext, TenantId tenantId, RuleChainId ruleChainId, String ruleChainName, RuleNodeId ruleNodeId) { 41 private RuleNodeActor(ActorSystemContext systemContext, TenantId tenantId, RuleChainId ruleChainId, String ruleChainName, RuleNodeId ruleNodeId) {
34 super(systemContext, tenantId, ruleNodeId); 42 super(systemContext, tenantId, ruleNodeId);
35 this.ruleChainName = ruleChainName; 43 this.ruleChainName = ruleChainName;
36 this.ruleChainId = ruleChainId; 44 this.ruleChainId = ruleChainId;
37 - setProcessor(new RuleNodeActorMessageProcessor(tenantId, this.ruleChainName, ruleNodeId, systemContext,  
38 - context().parent(), context().self())); 45 + this.ruleNodeId = ruleNodeId;
39 } 46 }
40 47
41 @Override 48 @Override
42 - protected boolean process(TbActorMsg msg) { 49 + protected RuleNodeActorMessageProcessor createProcessor(TbActorCtx ctx) {
  50 + return new RuleNodeActorMessageProcessor(tenantId, this.ruleChainName, ruleNodeId, systemContext, ctx.getParentRef(), ctx);
  51 + }
  52 +
  53 + @Override
  54 + protected boolean doProcess(TbActorMsg msg) {
43 switch (msg.getMsgType()) { 55 switch (msg.getMsgType()) {
44 case COMPONENT_LIFE_CYCLE_MSG: 56 case COMPONENT_LIFE_CYCLE_MSG:
45 onComponentLifecycleMsg((ComponentLifecycleMsg) msg); 57 onComponentLifecycleMsg((ComponentLifecycleMsg) msg);
@@ -93,8 +105,7 @@ public class RuleNodeActor extends ComponentActor<RuleNodeId, RuleNodeActorMessa @@ -93,8 +105,7 @@ public class RuleNodeActor extends ComponentActor<RuleNodeId, RuleNodeActorMessa
93 logAndPersist("onRuleMsg", ActorSystemContext.toException(msg.getError())); 105 logAndPersist("onRuleMsg", ActorSystemContext.toException(msg.getError()));
94 } 106 }
95 107
96 - public static class ActorCreator extends ContextBasedCreator<RuleNodeActor> {  
97 - private static final long serialVersionUID = 1L; 108 + public static class ActorCreator extends ContextBasedCreator {
98 109
99 private final TenantId tenantId; 110 private final TenantId tenantId;
100 private final RuleChainId ruleChainId; 111 private final RuleChainId ruleChainId;
@@ -111,7 +122,12 @@ public class RuleNodeActor extends ComponentActor<RuleNodeId, RuleNodeActorMessa @@ -111,7 +122,12 @@ public class RuleNodeActor extends ComponentActor<RuleNodeId, RuleNodeActorMessa
111 } 122 }
112 123
113 @Override 124 @Override
114 - public RuleNodeActor create() throws Exception { 125 + public TbActorId createActorId() {
  126 + return new TbEntityActorId(ruleNodeId);
  127 + }
  128 +
  129 + @Override
  130 + public TbActor createActor() {
115 return new RuleNodeActor(context, tenantId, ruleChainId, ruleChainName, ruleNodeId); 131 return new RuleNodeActor(context, tenantId, ruleChainId, ruleChainName, ruleNodeId);
116 } 132 }
117 } 133 }
@@ -15,11 +15,11 @@ @@ -15,11 +15,11 @@
15 */ 15 */
16 package org.thingsboard.server.actors.ruleChain; 16 package org.thingsboard.server.actors.ruleChain;
17 17
18 -import akka.actor.ActorContext;  
19 -import akka.actor.ActorRef;  
20 import org.thingsboard.rule.engine.api.TbNode; 18 import org.thingsboard.rule.engine.api.TbNode;
21 import org.thingsboard.rule.engine.api.TbNodeConfiguration; 19 import org.thingsboard.rule.engine.api.TbNodeConfiguration;
22 import org.thingsboard.server.actors.ActorSystemContext; 20 import org.thingsboard.server.actors.ActorSystemContext;
  21 +import org.thingsboard.server.actors.TbActorCtx;
  22 +import org.thingsboard.server.actors.TbActorRef;
23 import org.thingsboard.server.actors.shared.ComponentMsgProcessor; 23 import org.thingsboard.server.actors.shared.ComponentMsgProcessor;
24 import org.thingsboard.server.common.data.id.RuleNodeId; 24 import org.thingsboard.server.common.data.id.RuleNodeId;
25 import org.thingsboard.server.common.data.id.TenantId; 25 import org.thingsboard.server.common.data.id.TenantId;
@@ -34,13 +34,13 @@ import org.thingsboard.server.common.msg.queue.RuleNodeException; @@ -34,13 +34,13 @@ import org.thingsboard.server.common.msg.queue.RuleNodeException;
34 public class RuleNodeActorMessageProcessor extends ComponentMsgProcessor<RuleNodeId> { 34 public class RuleNodeActorMessageProcessor extends ComponentMsgProcessor<RuleNodeId> {
35 35
36 private final String ruleChainName; 36 private final String ruleChainName;
37 - private final ActorRef self; 37 + private final TbActorRef self;
38 private RuleNode ruleNode; 38 private RuleNode ruleNode;
39 private TbNode tbNode; 39 private TbNode tbNode;
40 private DefaultTbContext defaultCtx; 40 private DefaultTbContext defaultCtx;
41 41
42 RuleNodeActorMessageProcessor(TenantId tenantId, String ruleChainName, RuleNodeId ruleNodeId, ActorSystemContext systemContext 42 RuleNodeActorMessageProcessor(TenantId tenantId, String ruleChainName, RuleNodeId ruleNodeId, ActorSystemContext systemContext
43 - , ActorRef parent, ActorRef self) { 43 + , TbActorRef parent, TbActorRef self) {
44 super(systemContext, tenantId, ruleNodeId); 44 super(systemContext, tenantId, ruleNodeId);
45 this.ruleChainName = ruleChainName; 45 this.ruleChainName = ruleChainName;
46 this.self = self; 46 this.self = self;
@@ -49,7 +49,7 @@ public class RuleNodeActorMessageProcessor extends ComponentMsgProcessor<RuleNod @@ -49,7 +49,7 @@ public class RuleNodeActorMessageProcessor extends ComponentMsgProcessor<RuleNod
49 } 49 }
50 50
51 @Override 51 @Override
52 - public void start(ActorContext context) throws Exception { 52 + public void start(TbActorCtx context) throws Exception {
53 tbNode = initComponent(ruleNode); 53 tbNode = initComponent(ruleNode);
54 if (tbNode != null) { 54 if (tbNode != null) {
55 state = ComponentLifecycleState.ACTIVE; 55 state = ComponentLifecycleState.ACTIVE;
@@ -57,7 +57,7 @@ public class RuleNodeActorMessageProcessor extends ComponentMsgProcessor<RuleNod @@ -57,7 +57,7 @@ public class RuleNodeActorMessageProcessor extends ComponentMsgProcessor<RuleNod
57 } 57 }
58 58
59 @Override 59 @Override
60 - public void onUpdate(ActorContext context) throws Exception { 60 + public void onUpdate(TbActorCtx context) throws Exception {
61 RuleNode newRuleNode = systemContext.getRuleChainService().findRuleNodeById(tenantId, entityId); 61 RuleNode newRuleNode = systemContext.getRuleChainService().findRuleNodeById(tenantId, entityId);
62 boolean restartRequired = state != ComponentLifecycleState.ACTIVE || 62 boolean restartRequired = state != ComponentLifecycleState.ACTIVE ||
63 !(ruleNode.getType().equals(newRuleNode.getType()) && ruleNode.getConfiguration().equals(newRuleNode.getConfiguration())); 63 !(ruleNode.getType().equals(newRuleNode.getType()) && ruleNode.getConfiguration().equals(newRuleNode.getConfiguration()));
@@ -72,11 +72,11 @@ public class RuleNodeActorMessageProcessor extends ComponentMsgProcessor<RuleNod @@ -72,11 +72,11 @@ public class RuleNodeActorMessageProcessor extends ComponentMsgProcessor<RuleNod
72 } 72 }
73 73
74 @Override 74 @Override
75 - public void stop(ActorContext context) { 75 + public void stop(TbActorCtx context) {
76 if (tbNode != null) { 76 if (tbNode != null) {
77 tbNode.destroy(); 77 tbNode.destroy();
  78 + state = ComponentLifecycleState.SUSPENDED;
78 } 79 }
79 - context.stop(self);  
80 } 80 }
81 81
82 @Override 82 @Override
@@ -15,9 +15,9 @@ @@ -15,9 +15,9 @@
15 */ 15 */
16 package org.thingsboard.server.actors.ruleChain; 16 package org.thingsboard.server.actors.ruleChain;
17 17
18 -import akka.actor.ActorRef;  
19 import lombok.AllArgsConstructor; 18 import lombok.AllArgsConstructor;
20 import lombok.Data; 19 import lombok.Data;
  20 +import org.thingsboard.server.actors.TbActorRef;
21 import org.thingsboard.server.common.data.id.TenantId; 21 import org.thingsboard.server.common.data.id.TenantId;
22 import org.thingsboard.server.common.data.rule.RuleNode; 22 import org.thingsboard.server.common.data.rule.RuleNode;
23 23
@@ -28,7 +28,7 @@ import org.thingsboard.server.common.data.rule.RuleNode; @@ -28,7 +28,7 @@ import org.thingsboard.server.common.data.rule.RuleNode;
28 @AllArgsConstructor 28 @AllArgsConstructor
29 final class RuleNodeCtx { 29 final class RuleNodeCtx {
30 private final TenantId tenantId; 30 private final TenantId tenantId;
31 - private final ActorRef chainActor;  
32 - private final ActorRef selfActor; 31 + private final TbActorRef chainActor;
  32 + private final TbActorRef selfActor;
33 private RuleNode self; 33 private RuleNode self;
34 } 34 }
@@ -15,19 +15,23 @@ @@ -15,19 +15,23 @@
15 */ 15 */
16 package org.thingsboard.server.actors.service; 16 package org.thingsboard.server.actors.service;
17 17
18 -import akka.actor.ActorRef; 18 +import lombok.extern.slf4j.Slf4j;
19 import org.thingsboard.server.actors.ActorSystemContext; 19 import org.thingsboard.server.actors.ActorSystemContext;
  20 +import org.thingsboard.server.actors.TbActor;
  21 +import org.thingsboard.server.actors.TbActorCtx;
  22 +import org.thingsboard.server.actors.TbActorException;
20 import org.thingsboard.server.actors.shared.ComponentMsgProcessor; 23 import org.thingsboard.server.actors.shared.ComponentMsgProcessor;
21 import org.thingsboard.server.actors.stats.StatsPersistMsg; 24 import org.thingsboard.server.actors.stats.StatsPersistMsg;
22 import org.thingsboard.server.common.data.id.EntityId; 25 import org.thingsboard.server.common.data.id.EntityId;
23 import org.thingsboard.server.common.data.id.TenantId; 26 import org.thingsboard.server.common.data.id.TenantId;
24 import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; 27 import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
25 -import org.thingsboard.server.common.msg.queue.PartitionChangeMsg;  
26 import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; 28 import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg;
  29 +import org.thingsboard.server.common.msg.queue.PartitionChangeMsg;
27 30
28 /** 31 /**
29 * @author Andrew Shvayka 32 * @author Andrew Shvayka
30 */ 33 */
  34 +@Slf4j
31 public abstract class ComponentActor<T extends EntityId, P extends ComponentMsgProcessor<T>> extends ContextAwareActor { 35 public abstract class ComponentActor<T extends EntityId, P extends ComponentMsgProcessor<T>> extends ContextAwareActor {
32 36
33 private long lastPersistedErrorTs = 0L; 37 private long lastPersistedErrorTs = 0L;
@@ -43,30 +47,34 @@ public abstract class ComponentActor<T extends EntityId, P extends ComponentMsgP @@ -43,30 +47,34 @@ public abstract class ComponentActor<T extends EntityId, P extends ComponentMsgP
43 this.id = id; 47 this.id = id;
44 } 48 }
45 49
46 - protected void setProcessor(P processor) {  
47 - this.processor = processor;  
48 - } 50 + abstract protected P createProcessor(TbActorCtx ctx);
49 51
50 @Override 52 @Override
51 - public void preStart() { 53 + public void init(TbActorCtx ctx) throws TbActorException {
  54 + super.init(ctx);
  55 + this.processor = createProcessor(ctx);
  56 + initProcessor(ctx);
  57 + }
  58 +
  59 + protected void initProcessor(TbActorCtx ctx) throws TbActorException {
52 try { 60 try {
53 log.debug("[{}][{}][{}] Starting processor.", tenantId, id, id.getEntityType()); 61 log.debug("[{}][{}][{}] Starting processor.", tenantId, id, id.getEntityType());
54 - processor.start(context()); 62 + processor.start(ctx);
55 logLifecycleEvent(ComponentLifecycleEvent.STARTED); 63 logLifecycleEvent(ComponentLifecycleEvent.STARTED);
56 if (systemContext.isStatisticsEnabled()) { 64 if (systemContext.isStatisticsEnabled()) {
57 scheduleStatsPersistTick(); 65 scheduleStatsPersistTick();
58 } 66 }
59 } catch (Exception e) { 67 } catch (Exception e) {
60 - log.warn("[{}][{}] Failed to start {} processor.", tenantId, id, id.getEntityType());  
61 - log.warn("Error:", e); 68 + log.debug("[{}][{}] Failed to start {} processor.", tenantId, id, id.getEntityType(), e);
62 logAndPersist("OnStart", e, true); 69 logAndPersist("OnStart", e, true);
63 logLifecycleEvent(ComponentLifecycleEvent.STARTED, e); 70 logLifecycleEvent(ComponentLifecycleEvent.STARTED, e);
  71 + throw new TbActorException("Failed to init actor", e);
64 } 72 }
65 } 73 }
66 74
67 private void scheduleStatsPersistTick() { 75 private void scheduleStatsPersistTick() {
68 try { 76 try {
69 - processor.scheduleStatsPersistTick(context(), systemContext.getStatisticsPersistFrequency()); 77 + processor.scheduleStatsPersistTick(ctx, systemContext.getStatisticsPersistFrequency());
70 } catch (Exception e) { 78 } catch (Exception e) {
71 log.error("[{}][{}] Failed to schedule statistics store message. No statistics is going to be stored: {}", tenantId, id, e.getMessage()); 79 log.error("[{}][{}] Failed to schedule statistics store message. No statistics is going to be stored: {}", tenantId, id, e.getMessage());
72 logAndPersist("onScheduleStatsPersistMsg", e); 80 logAndPersist("onScheduleStatsPersistMsg", e);
@@ -74,10 +82,12 @@ public abstract class ComponentActor<T extends EntityId, P extends ComponentMsgP @@ -74,10 +82,12 @@ public abstract class ComponentActor<T extends EntityId, P extends ComponentMsgP
74 } 82 }
75 83
76 @Override 84 @Override
77 - public void postStop() { 85 + public void destroy() {
78 try { 86 try {
79 - log.debug("[{}][{}] Stopping processor.", tenantId, id, id.getEntityType());  
80 - processor.stop(context()); 87 + log.debug("[{}][{}][{}] Stopping processor.", tenantId, id, id.getEntityType());
  88 + if (processor != null) {
  89 + processor.stop(ctx);
  90 + }
81 logLifecycleEvent(ComponentLifecycleEvent.STOPPED); 91 logLifecycleEvent(ComponentLifecycleEvent.STOPPED);
82 } catch (Exception e) { 92 } catch (Exception e) {
83 log.warn("[{}][{}] Failed to stop {} processor: {}", tenantId, id, id.getEntityType(), e.getMessage()); 93 log.warn("[{}][{}] Failed to stop {} processor: {}", tenantId, id, id.getEntityType(), e.getMessage());
@@ -91,19 +101,20 @@ public abstract class ComponentActor<T extends EntityId, P extends ComponentMsgP @@ -91,19 +101,20 @@ public abstract class ComponentActor<T extends EntityId, P extends ComponentMsgP
91 try { 101 try {
92 switch (msg.getEvent()) { 102 switch (msg.getEvent()) {
93 case CREATED: 103 case CREATED:
94 - processor.onCreated(context()); 104 + processor.onCreated(ctx);
95 break; 105 break;
96 case UPDATED: 106 case UPDATED:
97 - processor.onUpdate(context()); 107 + processor.onUpdate(ctx);
98 break; 108 break;
99 case ACTIVATED: 109 case ACTIVATED:
100 - processor.onActivate(context()); 110 + processor.onActivate(ctx);
101 break; 111 break;
102 case SUSPENDED: 112 case SUSPENDED:
103 - processor.onSuspend(context()); 113 + processor.onSuspend(ctx);
104 break; 114 break;
105 case DELETED: 115 case DELETED:
106 - processor.onStop(context()); 116 + processor.onStop(ctx);
  117 + ctx.stop(ctx.getSelf());
107 break; 118 break;
108 default: 119 default:
109 break; 120 break;
@@ -125,7 +136,7 @@ public abstract class ComponentActor<T extends EntityId, P extends ComponentMsgP @@ -125,7 +136,7 @@ public abstract class ComponentActor<T extends EntityId, P extends ComponentMsgP
125 136
126 protected void onStatsPersistTick(EntityId entityId) { 137 protected void onStatsPersistTick(EntityId entityId) {
127 try { 138 try {
128 - systemContext.getStatsActor().tell(new StatsPersistMsg(messagesProcessed, errorsOccurred, tenantId, entityId), ActorRef.noSender()); 139 + systemContext.getStatsActor().tell(new StatsPersistMsg(messagesProcessed, errorsOccurred, tenantId, entityId));
129 resetStatsCounters(); 140 resetStatsCounters();
130 } catch (Exception e) { 141 } catch (Exception e) {
131 logAndPersist("onStatsPersistTick", e); 142 logAndPersist("onStatsPersistTick", e);
@@ -149,11 +160,11 @@ public abstract class ComponentActor<T extends EntityId, P extends ComponentMsgP @@ -149,11 +160,11 @@ public abstract class ComponentActor<T extends EntityId, P extends ComponentMsgP
149 errorsOccurred++; 160 errorsOccurred++;
150 String componentName = processor != null ? processor.getComponentName() : "Unknown"; 161 String componentName = processor != null ? processor.getComponentName() : "Unknown";
151 if (critical) { 162 if (critical) {
152 - log.warn("[{}][{}][{}] Failed to process {} msg: {}", id, tenantId, componentName, method);  
153 - log.warn("Critical Error: ", e); 163 + log.debug("[{}][{}][{}] Failed to process method: {}", id, tenantId, componentName, method);
  164 + log.debug("Critical Error: ", e);
154 } else { 165 } else {
155 - log.debug("[{}][{}][{}] Failed to process {} msg: {}", id, tenantId, componentName, method);  
156 - log.debug("Debug Error: ", e); 166 + log.trace("[{}][{}][{}] Failed to process method: {}", id, tenantId, componentName, method);
  167 + log.trace("Debug Error: ", e);
157 } 168 }
158 long ts = System.currentTimeMillis(); 169 long ts = System.currentTimeMillis();
159 if (ts - lastPersistedErrorTs > getErrorPersistFrequency()) { 170 if (ts - lastPersistedErrorTs > getErrorPersistFrequency()) {
@@ -15,17 +15,18 @@ @@ -15,17 +15,18 @@
15 */ 15 */
16 package org.thingsboard.server.actors.service; 16 package org.thingsboard.server.actors.service;
17 17
18 -import akka.actor.Terminated;  
19 -import akka.actor.UntypedAbstractActor; 18 +import lombok.extern.slf4j.Slf4j;
20 import org.slf4j.Logger; 19 import org.slf4j.Logger;
21 import org.slf4j.LoggerFactory; 20 import org.slf4j.LoggerFactory;
  21 +import org.thingsboard.server.actors.AbstractTbActor;
22 import org.thingsboard.server.actors.ActorSystemContext; 22 import org.thingsboard.server.actors.ActorSystemContext;
  23 +import org.thingsboard.server.actors.ProcessFailureStrategy;
  24 +import org.thingsboard.server.actors.TbActor;
  25 +import org.thingsboard.server.actors.TbActorCtx;
23 import org.thingsboard.server.common.msg.TbActorMsg; 26 import org.thingsboard.server.common.msg.TbActorMsg;
24 27
25 -  
26 -public abstract class ContextAwareActor extends UntypedAbstractActor {  
27 -  
28 - protected final Logger log = LoggerFactory.getLogger(getClass()); 28 +@Slf4j
  29 +public abstract class ContextAwareActor extends AbstractTbActor {
29 30
30 public static final int ENTITY_PACK_LIMIT = 1024; 31 public static final int ENTITY_PACK_LIMIT = 1024;
31 32
@@ -37,27 +38,29 @@ public abstract class ContextAwareActor extends UntypedAbstractActor { @@ -37,27 +38,29 @@ public abstract class ContextAwareActor extends UntypedAbstractActor {
37 } 38 }
38 39
39 @Override 40 @Override
40 - public void onReceive(Object msg) { 41 + public boolean process(TbActorMsg msg) {
41 if (log.isDebugEnabled()) { 42 if (log.isDebugEnabled()) {
42 log.debug("Processing msg: {}", msg); 43 log.debug("Processing msg: {}", msg);
43 } 44 }
44 - if (msg instanceof TbActorMsg) {  
45 - try {  
46 - if (!process((TbActorMsg) msg)) {  
47 - log.warn("Unknown message: {}!", msg);  
48 - }  
49 - } catch (Exception e) {  
50 - throw e;  
51 - }  
52 - } else if (msg instanceof Terminated) {  
53 - processTermination((Terminated) msg);  
54 - } else {  
55 - log.warn("Unknown message: {}!", msg); 45 + if (!doProcess(msg)) {
  46 + log.warn("Unprocessed message: {}!", msg);
56 } 47 }
  48 + return false;
57 } 49 }
58 50
59 - protected void processTermination(Terminated msg) { 51 + protected abstract boolean doProcess(TbActorMsg msg);
  52 +
  53 + @Override
  54 + public ProcessFailureStrategy onProcessFailure(Throwable t) {
  55 + log.debug("[{}] Processing failure: ", getActorRef().getActorId(), t);
  56 + return doProcessFailure(t);
60 } 57 }
61 58
62 - protected abstract boolean process(TbActorMsg msg); 59 + protected ProcessFailureStrategy doProcessFailure(Throwable t) {
  60 + if (t instanceof Error) {
  61 + return ProcessFailureStrategy.stop();
  62 + } else {
  63 + return ProcessFailureStrategy.resume();
  64 + }
  65 + }
63 } 66 }
@@ -15,12 +15,10 @@ @@ -15,12 +15,10 @@
15 */ 15 */
16 package org.thingsboard.server.actors.service; 16 package org.thingsboard.server.actors.service;
17 17
18 -import akka.japi.Creator;  
19 import org.thingsboard.server.actors.ActorSystemContext; 18 import org.thingsboard.server.actors.ActorSystemContext;
  19 +import org.thingsboard.server.actors.TbActorCreator;
20 20
21 -public abstract class ContextBasedCreator<T> implements Creator<T> {  
22 -  
23 - private static final long serialVersionUID = 1L; 21 +public abstract class ContextBasedCreator implements TbActorCreator {
24 22
25 protected final transient ActorSystemContext context; 23 protected final transient ActorSystemContext context;
26 24
@@ -15,85 +15,121 @@ @@ -15,85 +15,121 @@
15 */ 15 */
16 package org.thingsboard.server.actors.service; 16 package org.thingsboard.server.actors.service;
17 17
18 -import akka.actor.ActorRef;  
19 -import akka.actor.ActorSystem;  
20 -import akka.actor.Props;  
21 -import akka.actor.Terminated;  
22 import lombok.extern.slf4j.Slf4j; 18 import lombok.extern.slf4j.Slf4j;
23 import org.springframework.beans.factory.annotation.Autowired; 19 import org.springframework.beans.factory.annotation.Autowired;
24 import org.springframework.beans.factory.annotation.Value; 20 import org.springframework.beans.factory.annotation.Value;
25 import org.springframework.boot.context.event.ApplicationReadyEvent; 21 import org.springframework.boot.context.event.ApplicationReadyEvent;
26 import org.springframework.context.event.EventListener; 22 import org.springframework.context.event.EventListener;
27 -import org.springframework.scheduling.annotation.Scheduled;  
28 import org.springframework.stereotype.Service; 23 import org.springframework.stereotype.Service;
  24 +import org.thingsboard.common.util.ThingsBoardThreadFactory;
29 import org.thingsboard.server.actors.ActorSystemContext; 25 import org.thingsboard.server.actors.ActorSystemContext;
  26 +import org.thingsboard.server.actors.DefaultTbActorSystem;
  27 +import org.thingsboard.server.actors.TbActorId;
  28 +import org.thingsboard.server.actors.TbActorRef;
  29 +import org.thingsboard.server.actors.TbActorSystem;
  30 +import org.thingsboard.server.actors.TbActorSystemSettings;
30 import org.thingsboard.server.actors.app.AppActor; 31 import org.thingsboard.server.actors.app.AppActor;
31 import org.thingsboard.server.actors.app.AppInitMsg; 32 import org.thingsboard.server.actors.app.AppInitMsg;
32 import org.thingsboard.server.actors.stats.StatsActor; 33 import org.thingsboard.server.actors.stats.StatsActor;
33 import org.thingsboard.server.common.msg.queue.PartitionChangeMsg; 34 import org.thingsboard.server.common.msg.queue.PartitionChangeMsg;
34 import org.thingsboard.server.queue.discovery.PartitionChangeEvent; 35 import org.thingsboard.server.queue.discovery.PartitionChangeEvent;
35 -import scala.concurrent.Await;  
36 -import scala.concurrent.Future;  
37 -import scala.concurrent.duration.Duration;  
38 36
39 import javax.annotation.PostConstruct; 37 import javax.annotation.PostConstruct;
40 import javax.annotation.PreDestroy; 38 import javax.annotation.PreDestroy;
41 -import java.util.concurrent.atomic.AtomicInteger; 39 +import java.util.concurrent.ExecutorService;
  40 +import java.util.concurrent.Executors;
  41 +import java.util.concurrent.ScheduledExecutorService;
42 42
43 @Service 43 @Service
44 @Slf4j 44 @Slf4j
45 public class DefaultActorService implements ActorService { 45 public class DefaultActorService implements ActorService {
46 46
47 - private static final String ACTOR_SYSTEM_NAME = "Akka";  
48 -  
49 public static final String APP_DISPATCHER_NAME = "app-dispatcher"; 47 public static final String APP_DISPATCHER_NAME = "app-dispatcher";
50 - public static final String CORE_DISPATCHER_NAME = "core-dispatcher";  
51 - public static final String SYSTEM_RULE_DISPATCHER_NAME = "system-rule-dispatcher";  
52 - public static final String TENANT_RULE_DISPATCHER_NAME = "rule-dispatcher"; 48 + public static final String TENANT_DISPATCHER_NAME = "tenant-dispatcher";
  49 + public static final String DEVICE_DISPATCHER_NAME = "device-dispatcher";
  50 + public static final String RULE_DISPATCHER_NAME = "rule-dispatcher";
53 51
54 @Autowired 52 @Autowired
55 private ActorSystemContext actorContext; 53 private ActorSystemContext actorContext;
56 54
57 - private ActorSystem system; 55 + private TbActorSystem system;
  56 +
  57 + private TbActorRef appActor;
  58 +
  59 + @Value("${actors.system.throughput:5}")
  60 + private int actorThroughput;
  61 +
  62 + @Value("${actors.system.max_actor_init_attempts:10}")
  63 + private int maxActorInitAttempts;
  64 +
  65 + @Value("${actors.system.scheduler_pool_size:1}")
  66 + private int schedulerPoolSize;
  67 +
  68 + @Value("${actors.system.app_dispatcher_pool_size:1}")
  69 + private int appDispatcherSize;
  70 +
  71 + @Value("${actors.system.tenant_dispatcher_pool_size:2}")
  72 + private int tenantDispatcherSize;
58 73
59 - private ActorRef appActor; 74 + @Value("${actors.system.device_dispatcher_pool_size:4}")
  75 + private int deviceDispatcherSize;
  76 +
  77 + @Value("${actors.system.rule_dispatcher_pool_size:4}")
  78 + private int ruleDispatcherSize;
60 79
61 @PostConstruct 80 @PostConstruct
62 public void initActorSystem() { 81 public void initActorSystem() {
63 - log.info("Initializing Actor system."); 82 + log.info("Initializing actor system.");
64 actorContext.setActorService(this); 83 actorContext.setActorService(this);
65 - system = ActorSystem.create(ACTOR_SYSTEM_NAME, actorContext.getConfig()); 84 + TbActorSystemSettings settings = new TbActorSystemSettings(actorThroughput, schedulerPoolSize, maxActorInitAttempts);
  85 + system = new DefaultTbActorSystem(settings);
  86 +
  87 + system.createDispatcher(APP_DISPATCHER_NAME, initDispatcherExecutor(APP_DISPATCHER_NAME, appDispatcherSize));
  88 + system.createDispatcher(TENANT_DISPATCHER_NAME, initDispatcherExecutor(TENANT_DISPATCHER_NAME, tenantDispatcherSize));
  89 + system.createDispatcher(DEVICE_DISPATCHER_NAME, initDispatcherExecutor(DEVICE_DISPATCHER_NAME, deviceDispatcherSize));
  90 + system.createDispatcher(RULE_DISPATCHER_NAME, initDispatcherExecutor(RULE_DISPATCHER_NAME, ruleDispatcherSize));
  91 +
66 actorContext.setActorSystem(system); 92 actorContext.setActorSystem(system);
67 93
68 - appActor = system.actorOf(Props.create(new AppActor.ActorCreator(actorContext)).withDispatcher(APP_DISPATCHER_NAME), "appActor"); 94 + appActor = system.createRootActor(APP_DISPATCHER_NAME, new AppActor.ActorCreator(actorContext));
69 actorContext.setAppActor(appActor); 95 actorContext.setAppActor(appActor);
70 96
71 - ActorRef statsActor = system.actorOf(Props.create(new StatsActor.ActorCreator(actorContext)).withDispatcher(CORE_DISPATCHER_NAME), "statsActor"); 97 + TbActorRef statsActor = system.createRootActor(TENANT_DISPATCHER_NAME, new StatsActor.ActorCreator(actorContext, "StatsActor"));
72 actorContext.setStatsActor(statsActor); 98 actorContext.setStatsActor(statsActor);
73 99
74 log.info("Actor system initialized."); 100 log.info("Actor system initialized.");
75 } 101 }
76 102
  103 + private ExecutorService initDispatcherExecutor(String dispatcherName, int poolSize) {
  104 + if (poolSize == 0) {
  105 + int cores = Runtime.getRuntime().availableProcessors();
  106 + poolSize = Math.max(1, cores / 2);
  107 + }
  108 + if (poolSize == 1) {
  109 + return Executors.newSingleThreadExecutor(ThingsBoardThreadFactory.forName(dispatcherName));
  110 + } else {
  111 + return Executors.newWorkStealingPool(poolSize);
  112 + }
  113 + }
  114 +
77 @EventListener(ApplicationReadyEvent.class) 115 @EventListener(ApplicationReadyEvent.class)
78 public void onApplicationEvent(ApplicationReadyEvent applicationReadyEvent) { 116 public void onApplicationEvent(ApplicationReadyEvent applicationReadyEvent) {
79 log.info("Received application ready event. Sending application init message to actor system"); 117 log.info("Received application ready event. Sending application init message to actor system");
80 - appActor.tell(new AppInitMsg(), ActorRef.noSender()); 118 + appActor.tellWithHighPriority(new AppInitMsg());
81 } 119 }
82 120
83 @EventListener(PartitionChangeEvent.class) 121 @EventListener(PartitionChangeEvent.class)
84 public void onApplicationEvent(PartitionChangeEvent partitionChangeEvent) { 122 public void onApplicationEvent(PartitionChangeEvent partitionChangeEvent) {
85 log.info("Received partition change event."); 123 log.info("Received partition change event.");
86 - this.appActor.tell(new PartitionChangeMsg(partitionChangeEvent.getServiceQueueKey(), partitionChangeEvent.getPartitions()), ActorRef.noSender()); 124 + this.appActor.tellWithHighPriority(new PartitionChangeMsg(partitionChangeEvent.getServiceQueueKey(), partitionChangeEvent.getPartitions()));
87 } 125 }
88 126
89 @PreDestroy 127 @PreDestroy
90 public void stopActorSystem() { 128 public void stopActorSystem() {
91 - Future<Terminated> status = system.terminate();  
92 - try {  
93 - Terminated terminated = Await.result(status, Duration.Inf());  
94 - log.info("Actor system terminated: {}", terminated);  
95 - } catch (Exception e) {  
96 - log.error("Failed to terminate actor system.", e); 129 + if (system != null) {
  130 + log.info("Stopping actor system.");
  131 + system.stop();
  132 + log.info("Actor system stopped.");
97 } 133 }
98 } 134 }
99 135
@@ -15,18 +15,13 @@ @@ -15,18 +15,13 @@
15 */ 15 */
16 package org.thingsboard.server.actors.shared; 16 package org.thingsboard.server.actors.shared;
17 17
18 -import akka.actor.ActorContext;  
19 -import akka.actor.ActorRef;  
20 -import akka.actor.Scheduler;  
21 -import akka.event.LoggingAdapter;  
22 import com.fasterxml.jackson.databind.ObjectMapper; 18 import com.fasterxml.jackson.databind.ObjectMapper;
23 -import lombok.AllArgsConstructor;  
24 -import lombok.Data;  
25 import lombok.extern.slf4j.Slf4j; 19 import lombok.extern.slf4j.Slf4j;
26 import org.thingsboard.server.actors.ActorSystemContext; 20 import org.thingsboard.server.actors.ActorSystemContext;
27 -import scala.concurrent.ExecutionContextExecutor;  
28 -import scala.concurrent.duration.Duration; 21 +import org.thingsboard.server.actors.TbActorCtx;
  22 +import org.thingsboard.server.common.msg.TbActorMsg;
29 23
  24 +import java.util.concurrent.ScheduledExecutorService;
30 import java.util.concurrent.TimeUnit; 25 import java.util.concurrent.TimeUnit;
31 26
32 @Slf4j 27 @Slf4j
@@ -40,31 +35,16 @@ public abstract class AbstractContextAwareMsgProcessor { @@ -40,31 +35,16 @@ public abstract class AbstractContextAwareMsgProcessor {
40 this.systemContext = systemContext; 35 this.systemContext = systemContext;
41 } 36 }
42 37
43 - private Scheduler getScheduler() { 38 + private ScheduledExecutorService getScheduler() {
44 return systemContext.getScheduler(); 39 return systemContext.getScheduler();
45 } 40 }
46 41
47 - private ExecutionContextExecutor getSystemDispatcher() {  
48 - return systemContext.getActorSystem().dispatcher(); 42 + protected void schedulePeriodicMsgWithDelay(TbActorCtx ctx, TbActorMsg msg, long delayInMs, long periodInMs) {
  43 + systemContext.schedulePeriodicMsgWithDelay(ctx, msg, delayInMs, periodInMs);
49 } 44 }
50 45
51 - protected void schedulePeriodicMsgWithDelay(ActorContext ctx, Object msg, long delayInMs, long periodInMs) {  
52 - schedulePeriodicMsgWithDelay(msg, delayInMs, periodInMs, ctx.self()); 46 + protected void scheduleMsgWithDelay(TbActorCtx ctx, TbActorMsg msg, long delayInMs) {
  47 + systemContext.scheduleMsgWithDelay(ctx, msg, delayInMs);
53 } 48 }
54 49
55 - private void schedulePeriodicMsgWithDelay(Object msg, long delayInMs, long periodInMs, ActorRef target) {  
56 - log.debug("Scheduling periodic msg {} every {} ms with delay {} ms", msg, periodInMs, delayInMs);  
57 - getScheduler().schedule(Duration.create(delayInMs, TimeUnit.MILLISECONDS), Duration.create(periodInMs, TimeUnit.MILLISECONDS), target, msg, getSystemDispatcher(), null);  
58 - }  
59 -  
60 - protected void scheduleMsgWithDelay(ActorContext ctx, Object msg, long delayInMs) {  
61 - scheduleMsgWithDelay(msg, delayInMs, ctx.self());  
62 - }  
63 -  
64 - private void scheduleMsgWithDelay(Object msg, long delayInMs, ActorRef target) {  
65 - log.debug("Scheduling msg {} with delay {} ms", msg, delayInMs);  
66 - getScheduler().scheduleOnce(Duration.create(delayInMs, TimeUnit.MILLISECONDS), target, msg, getSystemDispatcher(), null);  
67 - }  
68 -  
69 -  
70 } 50 }
@@ -15,16 +15,15 @@ @@ -15,16 +15,15 @@
15 */ 15 */
16 package org.thingsboard.server.actors.shared; 16 package org.thingsboard.server.actors.shared;
17 17
18 -import akka.actor.ActorContext;  
19 import lombok.extern.slf4j.Slf4j; 18 import lombok.extern.slf4j.Slf4j;
20 import org.thingsboard.server.actors.ActorSystemContext; 19 import org.thingsboard.server.actors.ActorSystemContext;
  20 +import org.thingsboard.server.actors.TbActorCtx;
21 import org.thingsboard.server.actors.stats.StatsPersistTick; 21 import org.thingsboard.server.actors.stats.StatsPersistTick;
22 import org.thingsboard.server.common.data.id.EntityId; 22 import org.thingsboard.server.common.data.id.EntityId;
23 import org.thingsboard.server.common.data.id.TenantId; 23 import org.thingsboard.server.common.data.id.TenantId;
24 import org.thingsboard.server.common.data.plugin.ComponentLifecycleState; 24 import org.thingsboard.server.common.data.plugin.ComponentLifecycleState;
25 import org.thingsboard.server.common.msg.TbMsg; 25 import org.thingsboard.server.common.msg.TbMsg;
26 import org.thingsboard.server.common.msg.queue.PartitionChangeMsg; 26 import org.thingsboard.server.common.msg.queue.PartitionChangeMsg;
27 -import org.thingsboard.server.common.msg.queue.RuleEngineException;  
28 import org.thingsboard.server.common.msg.queue.RuleNodeException; 27 import org.thingsboard.server.common.msg.queue.RuleNodeException;
29 28
30 @Slf4j 29 @Slf4j
@@ -42,38 +41,38 @@ public abstract class ComponentMsgProcessor<T extends EntityId> extends Abstract @@ -42,38 +41,38 @@ public abstract class ComponentMsgProcessor<T extends EntityId> extends Abstract
42 41
43 public abstract String getComponentName(); 42 public abstract String getComponentName();
44 43
45 - public abstract void start(ActorContext context) throws Exception; 44 + public abstract void start(TbActorCtx context) throws Exception;
46 45
47 - public abstract void stop(ActorContext context) throws Exception; 46 + public abstract void stop(TbActorCtx context) throws Exception;
48 47
49 public abstract void onPartitionChangeMsg(PartitionChangeMsg msg) throws Exception; 48 public abstract void onPartitionChangeMsg(PartitionChangeMsg msg) throws Exception;
50 49
51 - public void onCreated(ActorContext context) throws Exception { 50 + public void onCreated(TbActorCtx context) throws Exception {
52 start(context); 51 start(context);
53 } 52 }
54 53
55 - public void onUpdate(ActorContext context) throws Exception { 54 + public void onUpdate(TbActorCtx context) throws Exception {
56 restart(context); 55 restart(context);
57 } 56 }
58 57
59 - public void onActivate(ActorContext context) throws Exception { 58 + public void onActivate(TbActorCtx context) throws Exception {
60 restart(context); 59 restart(context);
61 } 60 }
62 61
63 - public void onSuspend(ActorContext context) throws Exception { 62 + public void onSuspend(TbActorCtx context) throws Exception {
64 stop(context); 63 stop(context);
65 } 64 }
66 65
67 - public void onStop(ActorContext context) throws Exception { 66 + public void onStop(TbActorCtx context) throws Exception {
68 stop(context); 67 stop(context);
69 } 68 }
70 69
71 - private void restart(ActorContext context) throws Exception { 70 + private void restart(TbActorCtx context) throws Exception {
72 stop(context); 71 stop(context);
73 start(context); 72 start(context);
74 } 73 }
75 74
76 - public void scheduleStatsPersistTick(ActorContext context, long statsPersistFrequency) { 75 + public void scheduleStatsPersistTick(TbActorCtx context, long statsPersistFrequency) {
77 schedulePeriodicMsgWithDelay(context, new StatsPersistTick(), statsPersistFrequency, statsPersistFrequency); 76 schedulePeriodicMsgWithDelay(context, new StatsPersistTick(), statsPersistFrequency, statsPersistFrequency);
78 } 77 }
79 78
@@ -19,10 +19,15 @@ import com.fasterxml.jackson.databind.JsonNode; @@ -19,10 +19,15 @@ import com.fasterxml.jackson.databind.JsonNode;
19 import com.fasterxml.jackson.databind.ObjectMapper; 19 import com.fasterxml.jackson.databind.ObjectMapper;
20 import lombok.extern.slf4j.Slf4j; 20 import lombok.extern.slf4j.Slf4j;
21 import org.thingsboard.server.actors.ActorSystemContext; 21 import org.thingsboard.server.actors.ActorSystemContext;
  22 +import org.thingsboard.server.actors.TbActor;
  23 +import org.thingsboard.server.actors.TbActorCtx;
  24 +import org.thingsboard.server.actors.TbActorId;
  25 +import org.thingsboard.server.actors.TbStringActorId;
22 import org.thingsboard.server.actors.service.ContextAwareActor; 26 import org.thingsboard.server.actors.service.ContextAwareActor;
23 import org.thingsboard.server.actors.service.ContextBasedCreator; 27 import org.thingsboard.server.actors.service.ContextBasedCreator;
24 import org.thingsboard.server.common.data.DataConstants; 28 import org.thingsboard.server.common.data.DataConstants;
25 import org.thingsboard.server.common.data.Event; 29 import org.thingsboard.server.common.data.Event;
  30 +import org.thingsboard.server.common.msg.MsgType;
26 import org.thingsboard.server.common.msg.TbActorMsg; 31 import org.thingsboard.server.common.msg.TbActorMsg;
27 32
28 @Slf4j 33 @Slf4j
@@ -35,24 +40,17 @@ public class StatsActor extends ContextAwareActor { @@ -35,24 +40,17 @@ public class StatsActor extends ContextAwareActor {
35 } 40 }
36 41
37 @Override 42 @Override
38 - protected boolean process(TbActorMsg msg) {  
39 - //TODO Move everything here, to work with TbActorMsg\  
40 - return false;  
41 - }  
42 -  
43 - @Override  
44 - public void onReceive(Object msg) { 43 + protected boolean doProcess(TbActorMsg msg) {
45 log.debug("Received message: {}", msg); 44 log.debug("Received message: {}", msg);
46 - if (msg instanceof StatsPersistMsg) {  
47 - try {  
48 - onStatsPersistMsg((StatsPersistMsg) msg);  
49 - } catch (Exception e) {  
50 - log.warn("Failed to persist statistics: {}", msg, e);  
51 - } 45 + if (msg.getMsgType().equals(MsgType.STATS_PERSIST_MSG)) {
  46 + onStatsPersistMsg((StatsPersistMsg) msg);
  47 + return true;
  48 + } else {
  49 + return false;
52 } 50 }
53 } 51 }
54 52
55 - public void onStatsPersistMsg(StatsPersistMsg msg) throws Exception { 53 + public void onStatsPersistMsg(StatsPersistMsg msg) {
56 Event event = new Event(); 54 Event event = new Event();
57 event.setEntityId(msg.getEntityId()); 55 event.setEntityId(msg.getEntityId());
58 event.setTenantId(msg.getTenantId()); 56 event.setTenantId(msg.getTenantId());
@@ -65,15 +63,21 @@ public class StatsActor extends ContextAwareActor { @@ -65,15 +63,21 @@ public class StatsActor extends ContextAwareActor {
65 return mapper.createObjectNode().put("server", serviceId).put("messagesProcessed", messagesProcessed).put("errorsOccurred", errorsOccurred); 63 return mapper.createObjectNode().put("server", serviceId).put("messagesProcessed", messagesProcessed).put("errorsOccurred", errorsOccurred);
66 } 64 }
67 65
68 - public static class ActorCreator extends ContextBasedCreator<StatsActor> {  
69 - private static final long serialVersionUID = 1L; 66 + public static class ActorCreator extends ContextBasedCreator {
  67 + private final String actorId;
70 68
71 - public ActorCreator(ActorSystemContext context) { 69 + public ActorCreator(ActorSystemContext context, String actorId) {
72 super(context); 70 super(context);
  71 + this.actorId = actorId;
  72 + }
  73 +
  74 + @Override
  75 + public TbActorId createActorId() {
  76 + return new TbStringActorId(actorId);
73 } 77 }
74 78
75 @Override 79 @Override
76 - public StatsActor create() { 80 + public TbActor createActor() {
77 return new StatsActor(context); 81 return new StatsActor(context);
78 } 82 }
79 } 83 }
@@ -20,13 +20,21 @@ import lombok.Getter; @@ -20,13 +20,21 @@ import lombok.Getter;
20 import lombok.ToString; 20 import lombok.ToString;
21 import org.thingsboard.server.common.data.id.EntityId; 21 import org.thingsboard.server.common.data.id.EntityId;
22 import org.thingsboard.server.common.data.id.TenantId; 22 import org.thingsboard.server.common.data.id.TenantId;
  23 +import org.thingsboard.server.common.msg.MsgType;
  24 +import org.thingsboard.server.common.msg.TbActorMsg;
23 25
24 @AllArgsConstructor 26 @AllArgsConstructor
25 @Getter 27 @Getter
26 @ToString 28 @ToString
27 -public final class StatsPersistMsg { 29 +public final class StatsPersistMsg implements TbActorMsg {
  30 +
28 private long messagesProcessed; 31 private long messagesProcessed;
29 private long errorsOccurred; 32 private long errorsOccurred;
30 private TenantId tenantId; 33 private TenantId tenantId;
31 private EntityId entityId; 34 private EntityId entityId;
  35 +
  36 + @Override
  37 + public MsgType getMsgType() {
  38 + return MsgType.STATS_PERSIST_MSG;
  39 + }
32 } 40 }
@@ -15,16 +15,16 @@ @@ -15,16 +15,16 @@
15 */ 15 */
16 package org.thingsboard.server.actors.tenant; 16 package org.thingsboard.server.actors.tenant;
17 17
18 -import akka.actor.ActorInitializationException;  
19 -import akka.actor.ActorRef;  
20 -import akka.actor.LocalActorRef;  
21 -import akka.actor.OneForOneStrategy;  
22 -import akka.actor.Props;  
23 -import akka.actor.SupervisorStrategy;  
24 -import akka.actor.Terminated;  
25 -import com.google.common.collect.BiMap;  
26 -import com.google.common.collect.HashBiMap; 18 +import lombok.extern.slf4j.Slf4j;
27 import org.thingsboard.server.actors.ActorSystemContext; 19 import org.thingsboard.server.actors.ActorSystemContext;
  20 +import org.thingsboard.server.actors.TbActor;
  21 +import org.thingsboard.server.actors.TbActorCtx;
  22 +import org.thingsboard.server.actors.TbActorException;
  23 +import org.thingsboard.server.actors.TbActorId;
  24 +import org.thingsboard.server.actors.TbActorNotRegisteredException;
  25 +import org.thingsboard.server.actors.TbActorRef;
  26 +import org.thingsboard.server.actors.TbEntityActorId;
  27 +import org.thingsboard.server.actors.TbEntityTypeActorIdPredicate;
28 import org.thingsboard.server.actors.device.DeviceActorCreator; 28 import org.thingsboard.server.actors.device.DeviceActorCreator;
29 import org.thingsboard.server.actors.ruleChain.RuleChainManagerActor; 29 import org.thingsboard.server.actors.ruleChain.RuleChainManagerActor;
30 import org.thingsboard.server.actors.service.ContextBasedCreator; 30 import org.thingsboard.server.actors.service.ContextBasedCreator;
@@ -32,6 +32,7 @@ import org.thingsboard.server.actors.service.DefaultActorService; @@ -32,6 +32,7 @@ import org.thingsboard.server.actors.service.DefaultActorService;
32 import org.thingsboard.server.common.data.EntityType; 32 import org.thingsboard.server.common.data.EntityType;
33 import org.thingsboard.server.common.data.Tenant; 33 import org.thingsboard.server.common.data.Tenant;
34 import org.thingsboard.server.common.data.id.DeviceId; 34 import org.thingsboard.server.common.data.id.DeviceId;
  35 +import org.thingsboard.server.common.data.id.EntityId;
35 import org.thingsboard.server.common.data.id.RuleChainId; 36 import org.thingsboard.server.common.data.id.RuleChainId;
36 import org.thingsboard.server.common.data.id.TenantId; 37 import org.thingsboard.server.common.data.id.TenantId;
37 import org.thingsboard.server.common.data.rule.RuleChain; 38 import org.thingsboard.server.common.data.rule.RuleChain;
@@ -46,32 +47,25 @@ import org.thingsboard.server.common.msg.queue.PartitionChangeMsg; @@ -46,32 +47,25 @@ import org.thingsboard.server.common.msg.queue.PartitionChangeMsg;
46 import org.thingsboard.server.common.msg.queue.QueueToRuleEngineMsg; 47 import org.thingsboard.server.common.msg.queue.QueueToRuleEngineMsg;
47 import org.thingsboard.server.common.msg.queue.RuleEngineException; 48 import org.thingsboard.server.common.msg.queue.RuleEngineException;
48 import org.thingsboard.server.common.msg.queue.ServiceType; 49 import org.thingsboard.server.common.msg.queue.ServiceType;
49 -import scala.concurrent.duration.Duration;  
50 50
51 import java.util.List; 51 import java.util.List;
52 import java.util.Optional; 52 import java.util.Optional;
53 -import java.util.stream.Collectors;  
54 53
  54 +@Slf4j
55 public class TenantActor extends RuleChainManagerActor { 55 public class TenantActor extends RuleChainManagerActor {
56 56
57 - private final BiMap<DeviceId, ActorRef> deviceActors;  
58 private boolean isRuleEngineForCurrentTenant; 57 private boolean isRuleEngineForCurrentTenant;
59 private boolean isCore; 58 private boolean isCore;
60 59
61 private TenantActor(ActorSystemContext systemContext, TenantId tenantId) { 60 private TenantActor(ActorSystemContext systemContext, TenantId tenantId) {
62 super(systemContext, tenantId); 61 super(systemContext, tenantId);
63 - this.deviceActors = HashBiMap.create();  
64 - }  
65 -  
66 - @Override  
67 - public SupervisorStrategy supervisorStrategy() {  
68 - return strategy;  
69 } 62 }
70 63
71 boolean cantFindTenant = false; 64 boolean cantFindTenant = false;
72 65
73 @Override 66 @Override
74 - public void preStart() { 67 + public void init(TbActorCtx ctx) throws TbActorException {
  68 + super.init(ctx);
75 log.info("[{}] Starting tenant actor.", tenantId); 69 log.info("[{}] Starting tenant actor.", tenantId);
76 try { 70 try {
77 Tenant tenant = systemContext.getTenantService().findTenantById(tenantId); 71 Tenant tenant = systemContext.getTenantService().findTenantById(tenantId);
@@ -101,16 +95,18 @@ public class TenantActor extends RuleChainManagerActor { @@ -101,16 +95,18 @@ public class TenantActor extends RuleChainManagerActor {
101 } 95 }
102 } catch (Exception e) { 96 } catch (Exception e) {
103 log.warn("[{}] Unknown failure", tenantId, e); 97 log.warn("[{}] Unknown failure", tenantId, e);
  98 +// TODO: throw this in 3.1?
  99 +// throw new TbActorException("Failed to init actor", e);
104 } 100 }
105 } 101 }
106 102
107 @Override 103 @Override
108 - public void postStop() { 104 + public void destroy() {
109 log.info("[{}] Stopping tenant actor.", tenantId); 105 log.info("[{}] Stopping tenant actor.", tenantId);
110 } 106 }
111 107
112 @Override 108 @Override
113 - protected boolean process(TbActorMsg msg) { 109 + protected boolean doProcess(TbActorMsg msg) {
114 if (cantFindTenant) { 110 if (cantFindTenant) {
115 log.info("[{}] Processing missing Tenant msg: {}", tenantId, msg); 111 log.info("[{}] Processing missing Tenant msg: {}", tenantId, msg);
116 if (msg.getMsgType().equals(MsgType.QUEUE_TO_RULE_ENGINE_MSG)) { 112 if (msg.getMsgType().equals(MsgType.QUEUE_TO_RULE_ENGINE_MSG)) {
@@ -127,13 +123,13 @@ public class TenantActor extends RuleChainManagerActor { @@ -127,13 +123,13 @@ public class TenantActor extends RuleChainManagerActor {
127 //To Rule Chain Actors 123 //To Rule Chain Actors
128 broadcast(msg); 124 broadcast(msg);
129 } else if (ServiceType.TB_CORE.equals(serviceType)) { 125 } else if (ServiceType.TB_CORE.equals(serviceType)) {
130 - //To Device Actors  
131 - List<DeviceId> repartitionedDevices =  
132 - deviceActors.keySet().stream().filter(deviceId -> !isMyPartition(deviceId)).collect(Collectors.toList());  
133 - for (DeviceId deviceId : repartitionedDevices) {  
134 - ActorRef deviceActor = deviceActors.remove(deviceId);  
135 - context().stop(deviceActor);  
136 - } 126 + List<TbActorId> deviceActorIds = ctx.filterChildren(new TbEntityTypeActorIdPredicate(EntityType.DEVICE) {
  127 + @Override
  128 + protected boolean testEntityId(EntityId entityId) {
  129 + return super.testEntityId(entityId) && !isMyPartition(entityId);
  130 + }
  131 + });
  132 + deviceActorIds.forEach(id -> ctx.stop(id));
137 } 133 }
138 break; 134 break;
139 case COMPONENT_LIFE_CYCLE_MSG: 135 case COMPONENT_LIFE_CYCLE_MSG:
@@ -143,12 +139,14 @@ public class TenantActor extends RuleChainManagerActor { @@ -143,12 +139,14 @@ public class TenantActor extends RuleChainManagerActor {
143 onQueueToRuleEngineMsg((QueueToRuleEngineMsg) msg); 139 onQueueToRuleEngineMsg((QueueToRuleEngineMsg) msg);
144 break; 140 break;
145 case TRANSPORT_TO_DEVICE_ACTOR_MSG: 141 case TRANSPORT_TO_DEVICE_ACTOR_MSG:
  142 + onToDeviceActorMsg((DeviceAwareMsg) msg, false);
  143 + break;
146 case DEVICE_ATTRIBUTES_UPDATE_TO_DEVICE_ACTOR_MSG: 144 case DEVICE_ATTRIBUTES_UPDATE_TO_DEVICE_ACTOR_MSG:
147 case DEVICE_CREDENTIALS_UPDATE_TO_DEVICE_ACTOR_MSG: 145 case DEVICE_CREDENTIALS_UPDATE_TO_DEVICE_ACTOR_MSG:
148 case DEVICE_NAME_OR_TYPE_UPDATE_TO_DEVICE_ACTOR_MSG: 146 case DEVICE_NAME_OR_TYPE_UPDATE_TO_DEVICE_ACTOR_MSG:
149 case DEVICE_RPC_REQUEST_TO_DEVICE_ACTOR_MSG: 147 case DEVICE_RPC_REQUEST_TO_DEVICE_ACTOR_MSG:
150 case SERVER_RPC_RESPONSE_TO_DEVICE_ACTOR_MSG: 148 case SERVER_RPC_RESPONSE_TO_DEVICE_ACTOR_MSG:
151 - onToDeviceActorMsg((DeviceAwareMsg) msg); 149 + onToDeviceActorMsg((DeviceAwareMsg) msg, true);
152 break; 150 break;
153 case RULE_CHAIN_TO_RULE_CHAIN_MSG: 151 case RULE_CHAIN_TO_RULE_CHAIN_MSG:
154 onRuleChainMsg((RuleChainAwareMsg) msg); 152 onRuleChainMsg((RuleChainAwareMsg) msg);
@@ -159,8 +157,8 @@ public class TenantActor extends RuleChainManagerActor { @@ -159,8 +157,8 @@ public class TenantActor extends RuleChainManagerActor {
159 return true; 157 return true;
160 } 158 }
161 159
162 - private boolean isMyPartition(DeviceId deviceId) {  
163 - return systemContext.resolve(ServiceType.TB_CORE, tenantId, deviceId).isMyPartition(); 160 + private boolean isMyPartition(EntityId entityId) {
  161 + return systemContext.resolve(ServiceType.TB_CORE, tenantId, entityId).isMyPartition();
164 } 162 }
165 163
166 private void onQueueToRuleEngineMsg(QueueToRuleEngineMsg msg) { 164 private void onQueueToRuleEngineMsg(QueueToRuleEngineMsg msg) {
@@ -171,16 +169,15 @@ public class TenantActor extends RuleChainManagerActor { @@ -171,16 +169,15 @@ public class TenantActor extends RuleChainManagerActor {
171 TbMsg tbMsg = msg.getTbMsg(); 169 TbMsg tbMsg = msg.getTbMsg();
172 if (tbMsg.getRuleChainId() == null) { 170 if (tbMsg.getRuleChainId() == null) {
173 if (getRootChainActor() != null) { 171 if (getRootChainActor() != null) {
174 - getRootChainActor().tell(msg, self()); 172 + getRootChainActor().tell(msg);
175 } else { 173 } else {
176 tbMsg.getCallback().onFailure(new RuleEngineException("No Root Rule Chain available!")); 174 tbMsg.getCallback().onFailure(new RuleEngineException("No Root Rule Chain available!"));
177 log.info("[{}] No Root Chain: {}", tenantId, msg); 175 log.info("[{}] No Root Chain: {}", tenantId, msg);
178 } 176 }
179 } else { 177 } else {
180 - ActorRef ruleChainActor = get(tbMsg.getRuleChainId());  
181 - if (ruleChainActor != null) {  
182 - ruleChainActor.tell(msg, self());  
183 - } else { 178 + try {
  179 + ctx.tell(new TbEntityActorId(tbMsg.getRuleChainId()), msg);
  180 + } catch (TbActorNotRegisteredException ex) {
184 log.trace("Received message for non-existing rule chain: [{}]", tbMsg.getRuleChainId()); 181 log.trace("Received message for non-existing rule chain: [{}]", tbMsg.getRuleChainId());
185 //TODO: 3.1 Log it to dead letters queue; 182 //TODO: 3.1 Log it to dead letters queue;
186 tbMsg.getCallback().onSuccess(); 183 tbMsg.getCallback().onSuccess();
@@ -189,19 +186,24 @@ public class TenantActor extends RuleChainManagerActor { @@ -189,19 +186,24 @@ public class TenantActor extends RuleChainManagerActor {
189 } 186 }
190 187
191 private void onRuleChainMsg(RuleChainAwareMsg msg) { 188 private void onRuleChainMsg(RuleChainAwareMsg msg) {
192 - getOrCreateActor(context(), msg.getRuleChainId()).tell(msg, self()); 189 + getOrCreateActor(msg.getRuleChainId()).tell(msg);
193 } 190 }
194 191
195 - private void onToDeviceActorMsg(DeviceAwareMsg msg) { 192 + private void onToDeviceActorMsg(DeviceAwareMsg msg, boolean priority) {
196 if (!isCore) { 193 if (!isCore) {
197 log.warn("RECEIVED INVALID MESSAGE: {}", msg); 194 log.warn("RECEIVED INVALID MESSAGE: {}", msg);
198 } 195 }
199 - getOrCreateDeviceActor(msg.getDeviceId()).tell(msg, ActorRef.noSender()); 196 + TbActorRef deviceActor = getOrCreateDeviceActor(msg.getDeviceId());
  197 + if (priority) {
  198 + deviceActor.tellWithHighPriority(msg);
  199 + } else {
  200 + deviceActor.tell(msg);
  201 + }
200 } 202 }
201 203
202 private void onComponentLifecycleMsg(ComponentLifecycleMsg msg) { 204 private void onComponentLifecycleMsg(ComponentLifecycleMsg msg) {
203 if (isRuleEngineForCurrentTenant) { 205 if (isRuleEngineForCurrentTenant) {
204 - ActorRef target = getEntityActorRef(msg.getEntityId()); 206 + TbActorRef target = getEntityActorRef(msg.getEntityId());
205 if (target != null) { 207 if (target != null) {
206 if (msg.getEntityId().getEntityType() == EntityType.RULE_CHAIN) { 208 if (msg.getEntityId().getEntityType() == EntityType.RULE_CHAIN) {
207 RuleChain ruleChain = systemContext.getRuleChainService(). 209 RuleChain ruleChain = systemContext.getRuleChainService().
@@ -210,42 +212,20 @@ public class TenantActor extends RuleChainManagerActor { @@ -210,42 +212,20 @@ public class TenantActor extends RuleChainManagerActor {
210 visit(ruleChain, target); 212 visit(ruleChain, target);
211 } 213 }
212 } 214 }
213 - target.tell(msg, ActorRef.noSender()); 215 + target.tellWithHighPriority(msg);
214 } else { 216 } else {
215 log.debug("[{}] Invalid component lifecycle msg: {}", tenantId, msg); 217 log.debug("[{}] Invalid component lifecycle msg: {}", tenantId, msg);
216 } 218 }
217 } 219 }
218 } 220 }
219 221
220 - private ActorRef getOrCreateDeviceActor(DeviceId deviceId) {  
221 - return deviceActors.computeIfAbsent(deviceId, k -> {  
222 - log.debug("[{}][{}] Creating device actor.", tenantId, deviceId);  
223 - ActorRef deviceActor = context().actorOf(Props.create(new DeviceActorCreator(systemContext, tenantId, deviceId))  
224 - .withDispatcher(DefaultActorService.CORE_DISPATCHER_NAME)  
225 - , deviceId.toString());  
226 - context().watch(deviceActor);  
227 - log.debug("[{}][{}] Created device actor: {}.", tenantId, deviceId, deviceActor);  
228 - return deviceActor;  
229 - });  
230 - }  
231 -  
232 - @Override  
233 - protected void processTermination(Terminated message) {  
234 - ActorRef terminated = message.actor();  
235 - if (terminated instanceof LocalActorRef) {  
236 - boolean removed = deviceActors.inverse().remove(terminated) != null;  
237 - if (removed) {  
238 - log.debug("[{}] Removed actor:", terminated);  
239 - } else {  
240 - log.debug("Removed actor was not found in the device map!");  
241 - }  
242 - } else {  
243 - throw new IllegalStateException("Remote actors are not supported!");  
244 - } 222 + private TbActorRef getOrCreateDeviceActor(DeviceId deviceId) {
  223 + return ctx.getOrCreateChildActor(new TbEntityActorId(deviceId),
  224 + () -> DefaultActorService.DEVICE_DISPATCHER_NAME,
  225 + () -> new DeviceActorCreator(systemContext, tenantId, deviceId));
245 } 226 }
246 227
247 - public static class ActorCreator extends ContextBasedCreator<TenantActor> {  
248 - private static final long serialVersionUID = 1L; 228 + public static class ActorCreator extends ContextBasedCreator {
249 229
250 private final TenantId tenantId; 230 private final TenantId tenantId;
251 231
@@ -255,18 +235,14 @@ public class TenantActor extends RuleChainManagerActor { @@ -255,18 +235,14 @@ public class TenantActor extends RuleChainManagerActor {
255 } 235 }
256 236
257 @Override 237 @Override
258 - public TenantActor create() {  
259 - return new TenantActor(context, tenantId); 238 + public TbActorId createActorId() {
  239 + return new TbEntityActorId(tenantId);
260 } 240 }
261 - }  
262 241
263 - private final SupervisorStrategy strategy = new OneForOneStrategy(3, Duration.create("1 minute"), t -> {  
264 - log.warn("[{}] Unknown failure", tenantId, t);  
265 - if (t instanceof ActorInitializationException) {  
266 - return SupervisorStrategy.stop();  
267 - } else {  
268 - return SupervisorStrategy.resume(); 242 + @Override
  243 + public TbActor createActor() {
  244 + return new TenantActor(context, tenantId);
269 } 245 }
270 - }); 246 + }
271 247
272 } 248 }
@@ -15,7 +15,6 @@ @@ -15,7 +15,6 @@
15 */ 15 */
16 package org.thingsboard.server.service.queue; 16 package org.thingsboard.server.service.queue;
17 17
18 -import akka.actor.ActorRef;  
19 import lombok.extern.slf4j.Slf4j; 18 import lombok.extern.slf4j.Slf4j;
20 import org.springframework.beans.factory.annotation.Value; 19 import org.springframework.beans.factory.annotation.Value;
21 import org.springframework.scheduling.annotation.Scheduled; 20 import org.springframework.scheduling.annotation.Scheduled;
@@ -157,7 +156,7 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService<ToCore @@ -157,7 +156,7 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService<ToCore
157 tbCoreDeviceRpcService.forwardRpcRequestToDeviceActor((ToDeviceRpcRequestActorMsg) tbActorMsg); 156 tbCoreDeviceRpcService.forwardRpcRequestToDeviceActor((ToDeviceRpcRequestActorMsg) tbActorMsg);
158 } else { 157 } else {
159 log.trace("[{}] Forwarding message to App Actor {}", id, actorMsg.get()); 158 log.trace("[{}] Forwarding message to App Actor {}", id, actorMsg.get());
160 - actorContext.tell(actorMsg.get(), ActorRef.noSender()); 159 + actorContext.tell(actorMsg.get());
161 } 160 }
162 } 161 }
163 callback.onSuccess(); 162 callback.onSuccess();
@@ -168,7 +167,7 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService<ToCore @@ -168,7 +167,7 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService<ToCore
168 } 167 }
169 }); 168 });
170 if (!processingTimeoutLatch.await(packProcessingTimeout, TimeUnit.MILLISECONDS)) { 169 if (!processingTimeoutLatch.await(packProcessingTimeout, TimeUnit.MILLISECONDS)) {
171 - ctx.getAckMap().forEach((id, msg) -> log.warn("[{}] Timeout to process message: {}", id, msg.getValue())); 170 + ctx.getAckMap().forEach((id, msg) -> log.debug("[{}] Timeout to process message: {}", id, msg.getValue()));
172 ctx.getFailedMap().forEach((id, msg) -> log.warn("[{}] Failed to process message: {}", id, msg.getValue())); 171 ctx.getFailedMap().forEach((id, msg) -> log.warn("[{}] Failed to process message: {}", id, msg.getValue()));
173 } 172 }
174 mainConsumer.commit(); 173 mainConsumer.commit();
@@ -215,7 +214,7 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService<ToCore @@ -215,7 +214,7 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService<ToCore
215 Optional<TbActorMsg> actorMsg = encodingService.decode(toCoreNotification.getComponentLifecycleMsg().toByteArray()); 214 Optional<TbActorMsg> actorMsg = encodingService.decode(toCoreNotification.getComponentLifecycleMsg().toByteArray());
216 if (actorMsg.isPresent()) { 215 if (actorMsg.isPresent()) {
217 log.trace("[{}] Forwarding message to App Actor {}", id, actorMsg.get()); 216 log.trace("[{}] Forwarding message to App Actor {}", id, actorMsg.get());
218 - actorContext.tell(actorMsg.get(), ActorRef.noSender()); 217 + actorContext.tellWithHighPriority(actorMsg.get());
219 } 218 }
220 callback.onSuccess(); 219 callback.onSuccess();
221 } 220 }
@@ -293,7 +292,7 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService<ToCore @@ -293,7 +292,7 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService<ToCore
293 if (statsEnabled) { 292 if (statsEnabled) {
294 stats.log(toDeviceActorMsg); 293 stats.log(toDeviceActorMsg);
295 } 294 }
296 - actorContext.tell(new TransportToDeviceActorMsgWrapper(toDeviceActorMsg, callback), ActorRef.noSender()); 295 + actorContext.tell(new TransportToDeviceActorMsgWrapper(toDeviceActorMsg, callback));
297 } 296 }
298 297
299 private void throwNotHandled(Object msg, TbCallback callback) { 298 private void throwNotHandled(Object msg, TbCallback callback) {
@@ -15,7 +15,6 @@ @@ -15,7 +15,6 @@
15 */ 15 */
16 package org.thingsboard.server.service.queue; 16 package org.thingsboard.server.service.queue;
17 17
18 -import akka.actor.ActorRef;  
19 import com.google.protobuf.ProtocolStringList; 18 import com.google.protobuf.ProtocolStringList;
20 import lombok.extern.slf4j.Slf4j; 19 import lombok.extern.slf4j.Slf4j;
21 import org.springframework.beans.factory.annotation.Value; 20 import org.springframework.beans.factory.annotation.Value;
@@ -51,7 +50,6 @@ import org.thingsboard.server.service.queue.processing.TbRuleEngineProcessingStr @@ -51,7 +50,6 @@ import org.thingsboard.server.service.queue.processing.TbRuleEngineProcessingStr
51 import org.thingsboard.server.service.queue.processing.TbRuleEngineSubmitStrategy; 50 import org.thingsboard.server.service.queue.processing.TbRuleEngineSubmitStrategy;
52 import org.thingsboard.server.service.queue.processing.TbRuleEngineSubmitStrategyFactory; 51 import org.thingsboard.server.service.queue.processing.TbRuleEngineSubmitStrategyFactory;
53 import org.thingsboard.server.service.rpc.FromDeviceRpcResponse; 52 import org.thingsboard.server.service.rpc.FromDeviceRpcResponse;
54 -import org.thingsboard.server.service.rpc.TbCoreDeviceRpcService;  
55 import org.thingsboard.server.service.rpc.TbRuleEngineDeviceRpcService; 53 import org.thingsboard.server.service.rpc.TbRuleEngineDeviceRpcService;
56 import org.thingsboard.server.service.stats.RuleEngineStatisticsService; 54 import org.thingsboard.server.service.stats.RuleEngineStatisticsService;
57 55
@@ -168,7 +166,7 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService< @@ -168,7 +166,7 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService<
168 TbMsgCallback callback = new TbMsgPackCallback(id, tenantId, ctx); 166 TbMsgCallback callback = new TbMsgPackCallback(id, tenantId, ctx);
169 try { 167 try {
170 if (toRuleEngineMsg.getTbMsg() != null && !toRuleEngineMsg.getTbMsg().isEmpty()) { 168 if (toRuleEngineMsg.getTbMsg() != null && !toRuleEngineMsg.getTbMsg().isEmpty()) {
171 - forwardToRuleEngineActor(tenantId, toRuleEngineMsg, callback); 169 + forwardToRuleEngineActor(configuration.getName(), tenantId, toRuleEngineMsg, callback);
172 } else { 170 } else {
173 callback.onSuccess(); 171 callback.onSuccess();
174 } 172 }
@@ -182,7 +180,7 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService< @@ -182,7 +180,7 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService<
182 timeout = true; 180 timeout = true;
183 } 181 }
184 182
185 - TbRuleEngineProcessingResult result = new TbRuleEngineProcessingResult(timeout, ctx); 183 + TbRuleEngineProcessingResult result = new TbRuleEngineProcessingResult(configuration.getName(), timeout, ctx);
186 TbRuleEngineProcessingDecision decision = ackStrategy.analyze(result); 184 TbRuleEngineProcessingDecision decision = ackStrategy.analyze(result);
187 if (statsEnabled) { 185 if (statsEnabled) {
188 stats.log(result, decision.isCommit()); 186 stats.log(result, decision.isCommit());
@@ -232,7 +230,7 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService< @@ -232,7 +230,7 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService<
232 Optional<TbActorMsg> actorMsg = encodingService.decode(nfMsg.getComponentLifecycleMsg().toByteArray()); 230 Optional<TbActorMsg> actorMsg = encodingService.decode(nfMsg.getComponentLifecycleMsg().toByteArray());
233 if (actorMsg.isPresent()) { 231 if (actorMsg.isPresent()) {
234 log.trace("[{}] Forwarding message to App Actor {}", id, actorMsg.get()); 232 log.trace("[{}] Forwarding message to App Actor {}", id, actorMsg.get());
235 - actorContext.tell(actorMsg.get(), ActorRef.noSender()); 233 + actorContext.tellWithHighPriority(actorMsg.get());
236 } 234 }
237 callback.onSuccess(); 235 callback.onSuccess();
238 } else if (nfMsg.hasFromDeviceRpcResponse()) { 236 } else if (nfMsg.hasFromDeviceRpcResponse()) {
@@ -248,8 +246,8 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService< @@ -248,8 +246,8 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService<
248 } 246 }
249 } 247 }
250 248
251 - private void forwardToRuleEngineActor(TenantId tenantId, ToRuleEngineMsg toRuleEngineMsg, TbMsgCallback callback) {  
252 - TbMsg tbMsg = TbMsg.fromBytes(toRuleEngineMsg.getTbMsg().toByteArray(), callback); 249 + private void forwardToRuleEngineActor(String queueName, TenantId tenantId, ToRuleEngineMsg toRuleEngineMsg, TbMsgCallback callback) {
  250 + TbMsg tbMsg = TbMsg.fromBytes(queueName, toRuleEngineMsg.getTbMsg().toByteArray(), callback);
253 QueueToRuleEngineMsg msg; 251 QueueToRuleEngineMsg msg;
254 ProtocolStringList relationTypesList = toRuleEngineMsg.getRelationTypesList(); 252 ProtocolStringList relationTypesList = toRuleEngineMsg.getRelationTypesList();
255 Set<String> relationTypes = null; 253 Set<String> relationTypes = null;
@@ -261,7 +259,7 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService< @@ -261,7 +259,7 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService<
261 } 259 }
262 } 260 }
263 msg = new QueueToRuleEngineMsg(tenantId, tbMsg, relationTypes, toRuleEngineMsg.getFailureMessage()); 261 msg = new QueueToRuleEngineMsg(tenantId, tbMsg, relationTypes, toRuleEngineMsg.getFailureMessage());
264 - actorContext.tell(msg, ActorRef.noSender()); 262 + actorContext.tell(msg);
265 } 263 }
266 264
267 @Scheduled(fixedDelayString = "${queue.rule-engine.stats.print-interval-ms}") 265 @Scheduled(fixedDelayString = "${queue.rule-engine.stats.print-interval-ms}")
@@ -28,13 +28,16 @@ import java.util.concurrent.ConcurrentMap; @@ -28,13 +28,16 @@ import java.util.concurrent.ConcurrentMap;
28 public class TbRuleEngineProcessingResult { 28 public class TbRuleEngineProcessingResult {
29 29
30 @Getter 30 @Getter
  31 + private final String queueName;
  32 + @Getter
31 private final boolean success; 33 private final boolean success;
32 @Getter 34 @Getter
33 private final boolean timeout; 35 private final boolean timeout;
34 @Getter 36 @Getter
35 private final TbMsgPackProcessingContext ctx; 37 private final TbMsgPackProcessingContext ctx;
36 38
37 - public TbRuleEngineProcessingResult(boolean timeout, TbMsgPackProcessingContext ctx) { 39 + public TbRuleEngineProcessingResult(String queueName, boolean timeout, TbMsgPackProcessingContext ctx) {
  40 + this.queueName = queueName;
38 this.timeout = timeout; 41 this.timeout = timeout;
39 this.ctx = ctx; 42 this.ctx = ctx;
40 this.success = !timeout && ctx.getPendingMap().isEmpty() && ctx.getFailedMap().isEmpty(); 43 this.success = !timeout && ctx.getPendingMap().isEmpty() && ctx.getFailedMap().isEmpty();
@@ -100,7 +100,7 @@ public class TbRuleEngineProcessingStrategyFactory { @@ -100,7 +100,7 @@ public class TbRuleEngineProcessingStrategyFactory {
100 } 100 }
101 log.debug("[{}] Going to reprocess {} messages", queueName, toReprocess.size()); 101 log.debug("[{}] Going to reprocess {} messages", queueName, toReprocess.size());
102 if (log.isTraceEnabled()) { 102 if (log.isTraceEnabled()) {
103 - toReprocess.forEach((id, msg) -> log.trace("Going to reprocess [{}]: {}", id, TbMsg.fromBytes(msg.getValue().getTbMsg().toByteArray(), TbMsgCallback.EMPTY))); 103 + toReprocess.forEach((id, msg) -> log.trace("Going to reprocess [{}]: {}", id, TbMsg.fromBytes(result.getQueueName(), msg.getValue().getTbMsg().toByteArray(), TbMsgCallback.EMPTY)));
104 } 104 }
105 if (pauseBetweenRetries > 0) { 105 if (pauseBetweenRetries > 0) {
106 try { 106 try {
@@ -129,10 +129,10 @@ public class TbRuleEngineProcessingStrategyFactory { @@ -129,10 +129,10 @@ public class TbRuleEngineProcessingStrategyFactory {
129 log.debug("[{}] Reprocessing skipped for {} failed and {} timeout messages", queueName, result.getFailedMap().size(), result.getPendingMap().size()); 129 log.debug("[{}] Reprocessing skipped for {} failed and {} timeout messages", queueName, result.getFailedMap().size(), result.getPendingMap().size());
130 } 130 }
131 if (log.isTraceEnabled()) { 131 if (log.isTraceEnabled()) {
132 - result.getFailedMap().forEach((id, msg) -> log.trace("Failed messages [{}]: {}", id, TbMsg.fromBytes(msg.getValue().getTbMsg().toByteArray(), TbMsgCallback.EMPTY))); 132 + result.getFailedMap().forEach((id, msg) -> log.trace("Failed messages [{}]: {}", id, TbMsg.fromBytes(result.getQueueName(), msg.getValue().getTbMsg().toByteArray(), TbMsgCallback.EMPTY)));
133 } 133 }
134 if (log.isTraceEnabled()) { 134 if (log.isTraceEnabled()) {
135 - result.getPendingMap().forEach((id, msg) -> log.trace("Timeout messages [{}]: {}", id, TbMsg.fromBytes(msg.getValue().getTbMsg().toByteArray(), TbMsgCallback.EMPTY))); 135 + result.getPendingMap().forEach((id, msg) -> log.trace("Timeout messages [{}]: {}", id, TbMsg.fromBytes(result.getQueueName(), msg.getValue().getTbMsg().toByteArray(), TbMsgCallback.EMPTY)));
136 } 136 }
137 return new TbRuleEngineProcessingDecision(true, null); 137 return new TbRuleEngineProcessingDecision(true, null);
138 } 138 }
@@ -15,7 +15,6 @@ @@ -15,7 +15,6 @@
15 */ 15 */
16 package org.thingsboard.server.service.rpc; 16 package org.thingsboard.server.service.rpc;
17 17
18 -import akka.actor.ActorRef;  
19 import com.fasterxml.jackson.core.JsonProcessingException; 18 import com.fasterxml.jackson.core.JsonProcessingException;
20 import com.fasterxml.jackson.databind.ObjectMapper; 19 import com.fasterxml.jackson.databind.ObjectMapper;
21 import com.fasterxml.jackson.databind.node.ObjectNode; 20 import com.fasterxml.jackson.databind.node.ObjectNode;
@@ -122,7 +121,7 @@ public class DefaultTbCoreDeviceRpcService implements TbCoreDeviceRpcService { @@ -122,7 +121,7 @@ public class DefaultTbCoreDeviceRpcService implements TbCoreDeviceRpcService {
122 log.trace("[{}][{}] Processing local rpc call to device actor [{}]", request.getTenantId(), request.getId(), request.getDeviceId()); 121 log.trace("[{}][{}] Processing local rpc call to device actor [{}]", request.getTenantId(), request.getId(), request.getDeviceId());
123 UUID requestId = request.getId(); 122 UUID requestId = request.getId();
124 localToDeviceRpcRequests.put(requestId, rpcMsg); 123 localToDeviceRpcRequests.put(requestId, rpcMsg);
125 - actorContext.tell(rpcMsg, ActorRef.noSender()); 124 + actorContext.tellWithHighPriority(rpcMsg);
126 scheduleToDeviceTimeout(request, requestId); 125 scheduleToDeviceTimeout(request, requestId);
127 } 126 }
128 127
@@ -176,7 +175,7 @@ public class DefaultTbCoreDeviceRpcService implements TbCoreDeviceRpcService { @@ -176,7 +175,7 @@ public class DefaultTbCoreDeviceRpcService implements TbCoreDeviceRpcService {
176 } 175 }
177 176
178 private void scheduleToRuleEngineTimeout(ToDeviceRpcRequest request, UUID requestId) { 177 private void scheduleToRuleEngineTimeout(ToDeviceRpcRequest request, UUID requestId) {
179 - long timeout = Math.max(0, request.getExpirationTime() - System.currentTimeMillis()); 178 + long timeout = Math.max(0, request.getExpirationTime() - System.currentTimeMillis()) + TimeUnit.SECONDS.toMillis(1);
180 log.trace("[{}] processing to rule engine request.", requestId); 179 log.trace("[{}] processing to rule engine request.", requestId);
181 scheduler.schedule(() -> { 180 scheduler.schedule(() -> {
182 log.trace("[{}] timeout for processing to rule engine request.", requestId); 181 log.trace("[{}] timeout for processing to rule engine request.", requestId);
@@ -188,7 +187,7 @@ public class DefaultTbCoreDeviceRpcService implements TbCoreDeviceRpcService { @@ -188,7 +187,7 @@ public class DefaultTbCoreDeviceRpcService implements TbCoreDeviceRpcService {
188 } 187 }
189 188
190 private void scheduleToDeviceTimeout(ToDeviceRpcRequest request, UUID requestId) { 189 private void scheduleToDeviceTimeout(ToDeviceRpcRequest request, UUID requestId) {
191 - long timeout = Math.max(0, request.getExpirationTime() - System.currentTimeMillis()); 190 + long timeout = Math.max(0, request.getExpirationTime() - System.currentTimeMillis()) + TimeUnit.SECONDS.toMillis(1);
192 log.trace("[{}] processing to device request.", requestId); 191 log.trace("[{}] processing to device request.", requestId);
193 scheduler.schedule(() -> { 192 scheduler.schedule(() -> {
194 log.trace("[{}] timeout for to device request.", requestId); 193 log.trace("[{}] timeout for to device request.", requestId);
@@ -164,7 +164,7 @@ public class DefaultTbRuleEngineRpcService implements TbRuleEngineDeviceRpcServi @@ -164,7 +164,7 @@ public class DefaultTbRuleEngineRpcService implements TbRuleEngineDeviceRpcServi
164 } 164 }
165 165
166 private void scheduleTimeout(ToDeviceRpcRequest request, UUID requestId) { 166 private void scheduleTimeout(ToDeviceRpcRequest request, UUID requestId) {
167 - long timeout = Math.max(0, request.getExpirationTime() - System.currentTimeMillis()); 167 + long timeout = Math.max(0, request.getExpirationTime() - System.currentTimeMillis()) + TimeUnit.SECONDS.toMillis(1);
168 log.trace("[{}] processing the request: [{}]", this.hashCode(), requestId); 168 log.trace("[{}] processing the request: [{}]", this.hashCode(), requestId);
169 scheduler.schedule(() -> { 169 scheduler.schedule(() -> {
170 log.trace("[{}] timeout the request: [{}]", this.hashCode(), requestId); 170 log.trace("[{}] timeout the request: [{}]", this.hashCode(), requestId);
@@ -126,7 +126,7 @@ public abstract class AbstractNashornJsInvokeService extends AbstractJsInvokeSer @@ -126,7 +126,7 @@ public abstract class AbstractNashornJsInvokeService extends AbstractJsInvokeSer
126 scriptIdToNameMap.put(scriptId, functionName); 126 scriptIdToNameMap.put(scriptId, functionName);
127 return scriptId; 127 return scriptId;
128 } catch (Exception e) { 128 } catch (Exception e) {
129 - log.warn("Failed to compile JS script: {}", e.getMessage(), e); 129 + log.debug("Failed to compile JS script: {}", e.getMessage(), e);
130 throw new ExecutionException(e); 130 throw new ExecutionException(e);
131 } 131 }
132 }); 132 });
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 -  
17 -  
18 -akka {  
19 - # JVM shutdown, System.exit(-1), in case of a fatal error,  
20 - # such as OutOfMemoryError  
21 - jvm-exit-on-fatal-error = off  
22 - loglevel = "INFO"  
23 - loggers = ["akka.event.slf4j.Slf4jLogger"]  
24 -}  
25 -  
26 -# This dispatcher is used for app  
27 -app-dispatcher {  
28 - type = Dispatcher  
29 - executor = "fork-join-executor"  
30 - fork-join-executor {  
31 - # Min number of threads to cap factor-based parallelism number to  
32 - parallelism-min = 1  
33 - # Max number of threads to cap factor-based parallelism number to  
34 - parallelism-max = 1  
35 -  
36 - # The parallelism factor is used to determine thread pool size using the  
37 - # following formula: ceil(available processors * factor). Resulting size  
38 - # is then bounded by the parallelism-min and parallelism-max values.  
39 - parallelism-factor = 1.0  
40 - }  
41 - # How long time the dispatcher will wait for new actors until it shuts down  
42 - shutdown-timeout = 1s  
43 -  
44 - # Throughput defines the number of messages that are processed in a batch  
45 - # before the thread is returned to the pool. Set to 1 for as fair as possible.  
46 - throughput = 5  
47 -}  
48 -  
49 -# This dispatcher is used for rpc actors  
50 -rpc-dispatcher {  
51 - type = Dispatcher  
52 - executor = "fork-join-executor"  
53 - fork-join-executor {  
54 - # Min number of threads to cap factor-based parallelism number to  
55 - parallelism-min = 2  
56 - # Max number of threads to cap factor-based parallelism number to  
57 - parallelism-max = 8  
58 -  
59 - # The parallelism factor is used to determine thread pool size using the  
60 - # following formula: ceil(available processors * factor). Resulting size  
61 - # is then bounded by the parallelism-min and parallelism-max values.  
62 - parallelism-factor = 0.5  
63 - }  
64 - # How long time the dispatcher will wait for new actors until it shuts down  
65 - shutdown-timeout = 1s  
66 -  
67 - # Throughput defines the number of messages that are processed in a batch  
68 - # before the thread is returned to the pool. Set to 1 for as fair as possible.  
69 - throughput = 5  
70 -}  
71 -  
72 -# This dispatcher is used for auth  
73 -core-dispatcher {  
74 - type = Dispatcher  
75 - executor = "fork-join-executor"  
76 - fork-join-executor {  
77 - # Min number of threads to cap factor-based parallelism number to  
78 - parallelism-min = 2  
79 - # Max number of threads to cap factor-based parallelism number to  
80 - parallelism-max = 12  
81 -  
82 - # The parallelism factor is used to determine thread pool size using the  
83 - # following formula: ceil(available processors * factor). Resulting size  
84 - # is then bounded by the parallelism-min and parallelism-max values.  
85 - parallelism-factor = 0.25  
86 - }  
87 - # How long time the dispatcher will wait for new actors until it shuts down  
88 - shutdown-timeout = 1s  
89 -  
90 - # Throughput defines the number of messages that are processed in a batch  
91 - # before the thread is returned to the pool. Set to 1 for as fair as possible.  
92 - throughput = 5  
93 -}  
94 -  
95 -# This dispatcher is used for system rule chains and rule node actors  
96 -system-rule-dispatcher {  
97 - type = Dispatcher  
98 - executor = "fork-join-executor"  
99 - fork-join-executor {  
100 - # Min number of threads to cap factor-based parallelism number to  
101 - parallelism-min = 2  
102 - # Max number of threads to cap factor-based parallelism number to  
103 - parallelism-max = 12  
104 -  
105 - # The parallelism factor is used to determine thread pool size using the  
106 - # following formula: ceil(available processors * factor). Resulting size  
107 - # is then bounded by the parallelism-min and parallelism-max values.  
108 - parallelism-factor = 0.25  
109 - }  
110 - # How long time the dispatcher will wait for new actors until it shuts down  
111 - shutdown-timeout = 1s  
112 -  
113 - # Throughput defines the number of messages that are processed in a batch  
114 - # before the thread is returned to the pool. Set to 1 for as fair as possible.  
115 - throughput = 5  
116 -}  
117 -  
118 -# This dispatcher is used for tenant rule chains and rule node actors  
119 -rule-dispatcher {  
120 - type = Dispatcher  
121 - executor = "fork-join-executor"  
122 - fork-join-executor {  
123 - # Min number of threads to cap factor-based parallelism number to  
124 - parallelism-min = 2  
125 - # Max number of threads to cap factor-based parallelism number to  
126 - parallelism-max = 12  
127 -  
128 - # The parallelism factor is used to determine thread pool size using the  
129 - # following formula: ceil(available processors * factor). Resulting size  
130 - # is then bounded by the parallelism-min and parallelism-max values.  
131 - parallelism-factor = 0.25  
132 - }  
133 - # How long time the dispatcher will wait for new actors until it shuts down  
134 - shutdown-timeout = 1s  
135 -  
136 - # Throughput defines the number of messages that are processed in a batch  
137 - # before the thread is returned to the pool. Set to 1 for as fair as possible.  
138 - throughput = 5  
139 -}  
@@ -27,7 +27,6 @@ @@ -27,7 +27,6 @@
27 27
28 <logger name="org.thingsboard.server" level="INFO" /> 28 <logger name="org.thingsboard.server" level="INFO" />
29 <logger name="org.thingsboard.server.service.edge" level="TRACE" /> 29 <logger name="org.thingsboard.server.service.edge" level="TRACE" />
30 - <logger name="akka" level="INFO" />  
31 30
32 <!-- <logger name="org.thingsboard.server.service.queue" level="TRACE" />--> 31 <!-- <logger name="org.thingsboard.server.service.queue" level="TRACE" />-->
33 <!-- <logger name="org.thingsboard.server.service.transport" level="TRACE" />--> 32 <!-- <logger name="org.thingsboard.server.service.transport" level="TRACE" />-->
@@ -281,6 +281,14 @@ sql: @@ -281,6 +281,14 @@ sql:
281 281
282 # Actor system parameters 282 # Actor system parameters
283 actors: 283 actors:
  284 + system:
  285 + throughput: "${ACTORS_SYSTEM_THROUGHPUT:5}"
  286 + scheduler_pool_size: "${ACTORS_SYSTEM_SCHEDULER_POOL_SIZE:1}"
  287 + max_actor_init_attempts: "${ACTORS_SYSTEM_MAX_ACTOR_INIT_ATTEMPTS:10}"
  288 + app_dispatcher_pool_size: "${ACTORS_SYSTEM_APP_DISPATCHER_POOL_SIZE:1}"
  289 + tenant_dispatcher_pool_size: "${ACTORS_SYSTEM_TENANT_DISPATCHER_POOL_SIZE:2}"
  290 + device_dispatcher_pool_size: "${ACTORS_SYSTEM_DEVICE_DISPATCHER_POOL_SIZE:4}"
  291 + rule_dispatcher_pool_size: "${ACTORS_SYSTEM_RULE_DISPATCHER_POOL_SIZE:4}"
284 tenant: 292 tenant:
285 create_components_on_init: "${ACTORS_TENANT_CREATE_COMPONENTS_ON_INIT:true}" 293 create_components_on_init: "${ACTORS_TENANT_CREATE_COMPONENTS_ON_INIT:true}"
286 session: 294 session:
@@ -318,11 +326,6 @@ actors: @@ -318,11 +326,6 @@ actors:
318 enabled: "${ACTORS_STATISTICS_ENABLED:true}" 326 enabled: "${ACTORS_STATISTICS_ENABLED:true}"
319 js_print_interval_ms: "${ACTORS_JS_STATISTICS_PRINT_INTERVAL_MS:10000}" 327 js_print_interval_ms: "${ACTORS_JS_STATISTICS_PRINT_INTERVAL_MS:10000}"
320 persist_frequency: "${ACTORS_STATISTICS_PERSIST_FREQUENCY:3600000}" 328 persist_frequency: "${ACTORS_STATISTICS_PERSIST_FREQUENCY:3600000}"
321 - queue:  
322 - # Enable/disable persistence of un-processed messages to the queue  
323 - enabled: "${ACTORS_QUEUE_ENABLED:true}"  
324 - # Maximum allowed timeout for persistence into the queue  
325 - timeout: "${ACTORS_QUEUE_PERSISTENCE_TIMEOUT:30000}"  
326 329
327 cache: 330 cache:
328 # caffeine or redis 331 # caffeine or redis
@@ -26,7 +26,9 @@ import java.util.Arrays; @@ -26,7 +26,9 @@ import java.util.Arrays;
26 26
27 @RunWith(ClasspathSuite.class) 27 @RunWith(ClasspathSuite.class)
28 @ClasspathSuite.ClassnameFilters({ 28 @ClasspathSuite.ClassnameFilters({
29 - "org.thingsboard.server.mqtt.rpc.sql.*Test", "org.thingsboard.server.mqtt.telemetry.sql.*Test"}) 29 + "org.thingsboard.server.mqtt.rpc.sql.*Test",
  30 + "org.thingsboard.server.mqtt.telemetry.sql.*Test"
  31 +})
30 public class MqttSqlTestSuite { 32 public class MqttSqlTestSuite {
31 33
32 @ClassRule 34 @ClassRule
@@ -136,7 +136,7 @@ public abstract class AbstractMqttServerSideRpcIntegrationTest extends AbstractC @@ -136,7 +136,7 @@ public abstract class AbstractMqttServerSideRpcIntegrationTest extends AbstractC
136 String setGpioRequest = "{\"method\":\"setGpio\",\"params\":{\"pin\": \"24\",\"value\": 1},\"timeout\": 6000}"; 136 String setGpioRequest = "{\"method\":\"setGpio\",\"params\":{\"pin\": \"24\",\"value\": 1},\"timeout\": 6000}";
137 String deviceId = savedDevice.getId().getId().toString(); 137 String deviceId = savedDevice.getId().getId().toString();
138 138
139 - doPostAsync("/api/plugins/rpc/oneway/" + deviceId, setGpioRequest, String.class, status().isRequestTimeout(), 139 + doPostAsync("/api/plugins/rpc/oneway/" + deviceId, setGpioRequest, String.class, status().is(409),
140 asyncContextTimeoutToUseRpcPlugin); 140 asyncContextTimeoutToUseRpcPlugin);
141 } 141 }
142 142
@@ -193,7 +193,7 @@ public abstract class AbstractMqttServerSideRpcIntegrationTest extends AbstractC @@ -193,7 +193,7 @@ public abstract class AbstractMqttServerSideRpcIntegrationTest extends AbstractC
193 String setGpioRequest = "{\"method\":\"setGpio\",\"params\":{\"pin\": \"27\",\"value\": 1},\"timeout\": 6000}"; 193 String setGpioRequest = "{\"method\":\"setGpio\",\"params\":{\"pin\": \"27\",\"value\": 1},\"timeout\": 6000}";
194 String deviceId = savedDevice.getId().getId().toString(); 194 String deviceId = savedDevice.getId().getId().toString();
195 195
196 - doPostAsync("/api/plugins/rpc/twoway/" + deviceId, setGpioRequest, String.class, status().isRequestTimeout(), 196 + doPostAsync("/api/plugins/rpc/twoway/" + deviceId, setGpioRequest, String.class, status().is(409),
197 asyncContextTimeoutToUseRpcPlugin); 197 asyncContextTimeoutToUseRpcPlugin);
198 } 198 }
199 199
@@ -15,8 +15,6 @@ @@ -15,8 +15,6 @@
15 */ 15 */
16 package org.thingsboard.server.rules.flow; 16 package org.thingsboard.server.rules.flow;
17 17
18 -import akka.actor.ActorRef;  
19 -import com.datastax.driver.core.utils.UUIDs;  
20 import lombok.extern.slf4j.Slf4j; 18 import lombok.extern.slf4j.Slf4j;
21 import org.junit.After; 19 import org.junit.After;
22 import org.junit.Assert; 20 import org.junit.Assert;
@@ -26,7 +24,6 @@ import org.mockito.Mockito; @@ -26,7 +24,6 @@ import org.mockito.Mockito;
26 import org.springframework.beans.factory.annotation.Autowired; 24 import org.springframework.beans.factory.annotation.Autowired;
27 import org.thingsboard.rule.engine.metadata.TbGetAttributesNodeConfiguration; 25 import org.thingsboard.rule.engine.metadata.TbGetAttributesNodeConfiguration;
28 import org.thingsboard.server.actors.ActorSystemContext; 26 import org.thingsboard.server.actors.ActorSystemContext;
29 -import org.thingsboard.server.actors.service.ActorService;  
30 import org.thingsboard.server.common.data.*; 27 import org.thingsboard.server.common.data.*;
31 import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry; 28 import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry;
32 import org.thingsboard.server.common.data.kv.StringDataEntry; 29 import org.thingsboard.server.common.data.kv.StringDataEntry;
@@ -36,7 +33,6 @@ import org.thingsboard.server.common.data.rule.RuleChainMetaData; @@ -36,7 +33,6 @@ import org.thingsboard.server.common.data.rule.RuleChainMetaData;
36 import org.thingsboard.server.common.data.rule.RuleNode; 33 import org.thingsboard.server.common.data.rule.RuleNode;
37 import org.thingsboard.server.common.data.security.Authority; 34 import org.thingsboard.server.common.data.security.Authority;
38 import org.thingsboard.server.common.msg.TbMsg; 35 import org.thingsboard.server.common.msg.TbMsg;
39 -import org.thingsboard.server.common.msg.TbMsgDataType;  
40 import org.thingsboard.server.common.msg.TbMsgMetaData; 36 import org.thingsboard.server.common.msg.TbMsgMetaData;
41 import org.thingsboard.server.common.msg.queue.QueueToRuleEngineMsg; 37 import org.thingsboard.server.common.msg.queue.QueueToRuleEngineMsg;
42 import org.thingsboard.server.common.msg.queue.TbMsgCallback; 38 import org.thingsboard.server.common.msg.queue.TbMsgCallback;
@@ -151,7 +147,7 @@ public abstract class AbstractRuleEngineFlowIntegrationTest extends AbstractRule @@ -151,7 +147,7 @@ public abstract class AbstractRuleEngineFlowIntegrationTest extends AbstractRule
151 TbMsg tbMsg = TbMsg.newMsg("CUSTOM", device.getId(), new TbMsgMetaData(), "{}", tbMsgCallback); 147 TbMsg tbMsg = TbMsg.newMsg("CUSTOM", device.getId(), new TbMsgMetaData(), "{}", tbMsgCallback);
152 QueueToRuleEngineMsg qMsg = new QueueToRuleEngineMsg(savedTenant.getId(), tbMsg, null, null); 148 QueueToRuleEngineMsg qMsg = new QueueToRuleEngineMsg(savedTenant.getId(), tbMsg, null, null);
153 // Pushing Message to the system 149 // Pushing Message to the system
154 - actorSystem.tell(qMsg, ActorRef.noSender()); 150 + actorSystem.tell(qMsg);
155 Mockito.verify(tbMsgCallback, Mockito.timeout(10000)).onSuccess(); 151 Mockito.verify(tbMsgCallback, Mockito.timeout(10000)).onSuccess();
156 152
157 TimePageData<Event> eventsPage = getDebugEvents(savedTenant.getId(), ruleChain.getFirstRuleNodeId(), 1000); 153 TimePageData<Event> eventsPage = getDebugEvents(savedTenant.getId(), ruleChain.getFirstRuleNodeId(), 1000);
@@ -263,7 +259,7 @@ public abstract class AbstractRuleEngineFlowIntegrationTest extends AbstractRule @@ -263,7 +259,7 @@ public abstract class AbstractRuleEngineFlowIntegrationTest extends AbstractRule
263 TbMsg tbMsg = TbMsg.newMsg("CUSTOM", device.getId(), new TbMsgMetaData(), "{}", tbMsgCallback); 259 TbMsg tbMsg = TbMsg.newMsg("CUSTOM", device.getId(), new TbMsgMetaData(), "{}", tbMsgCallback);
264 QueueToRuleEngineMsg qMsg = new QueueToRuleEngineMsg(savedTenant.getId(), tbMsg, null, null); 260 QueueToRuleEngineMsg qMsg = new QueueToRuleEngineMsg(savedTenant.getId(), tbMsg, null, null);
265 // Pushing Message to the system 261 // Pushing Message to the system
266 - actorSystem.tell(qMsg, ActorRef.noSender()); 262 + actorSystem.tell(qMsg);
267 263
268 Mockito.verify(tbMsgCallback, Mockito.timeout(10000)).onSuccess(); 264 Mockito.verify(tbMsgCallback, Mockito.timeout(10000)).onSuccess();
269 265
@@ -15,8 +15,6 @@ @@ -15,8 +15,6 @@
15 */ 15 */
16 package org.thingsboard.server.rules.lifecycle; 16 package org.thingsboard.server.rules.lifecycle;
17 17
18 -import akka.actor.ActorRef;  
19 -import com.datastax.driver.core.utils.UUIDs;  
20 import lombok.extern.slf4j.Slf4j; 18 import lombok.extern.slf4j.Slf4j;
21 import org.junit.After; 19 import org.junit.After;
22 import org.junit.Assert; 20 import org.junit.Assert;
@@ -26,7 +24,6 @@ import org.mockito.Mockito; @@ -26,7 +24,6 @@ import org.mockito.Mockito;
26 import org.springframework.beans.factory.annotation.Autowired; 24 import org.springframework.beans.factory.annotation.Autowired;
27 import org.thingsboard.rule.engine.metadata.TbGetAttributesNodeConfiguration; 25 import org.thingsboard.rule.engine.metadata.TbGetAttributesNodeConfiguration;
28 import org.thingsboard.server.actors.ActorSystemContext; 26 import org.thingsboard.server.actors.ActorSystemContext;
29 -import org.thingsboard.server.actors.service.ActorService;  
30 import org.thingsboard.server.common.data.DataConstants; 27 import org.thingsboard.server.common.data.DataConstants;
31 import org.thingsboard.server.common.data.Device; 28 import org.thingsboard.server.common.data.Device;
32 import org.thingsboard.server.common.data.Event; 29 import org.thingsboard.server.common.data.Event;
@@ -40,7 +37,6 @@ import org.thingsboard.server.common.data.rule.RuleChainMetaData; @@ -40,7 +37,6 @@ import org.thingsboard.server.common.data.rule.RuleChainMetaData;
40 import org.thingsboard.server.common.data.rule.RuleNode; 37 import org.thingsboard.server.common.data.rule.RuleNode;
41 import org.thingsboard.server.common.data.security.Authority; 38 import org.thingsboard.server.common.data.security.Authority;
42 import org.thingsboard.server.common.msg.TbMsg; 39 import org.thingsboard.server.common.msg.TbMsg;
43 -import org.thingsboard.server.common.msg.TbMsgDataType;  
44 import org.thingsboard.server.common.msg.TbMsgMetaData; 40 import org.thingsboard.server.common.msg.TbMsgMetaData;
45 import org.thingsboard.server.common.msg.queue.QueueToRuleEngineMsg; 41 import org.thingsboard.server.common.msg.queue.QueueToRuleEngineMsg;
46 import org.thingsboard.server.common.msg.queue.TbMsgCallback; 42 import org.thingsboard.server.common.msg.queue.TbMsgCallback;
@@ -142,7 +138,7 @@ public abstract class AbstractRuleEngineLifecycleIntegrationTest extends Abstrac @@ -142,7 +138,7 @@ public abstract class AbstractRuleEngineLifecycleIntegrationTest extends Abstrac
142 TbMsg tbMsg = TbMsg.newMsg("CUSTOM", device.getId(), new TbMsgMetaData(), "{}", tbMsgCallback); 138 TbMsg tbMsg = TbMsg.newMsg("CUSTOM", device.getId(), new TbMsgMetaData(), "{}", tbMsgCallback);
143 QueueToRuleEngineMsg qMsg = new QueueToRuleEngineMsg(savedTenant.getId(), tbMsg, null, null); 139 QueueToRuleEngineMsg qMsg = new QueueToRuleEngineMsg(savedTenant.getId(), tbMsg, null, null);
144 // Pushing Message to the system 140 // Pushing Message to the system
145 - actorSystem.tell(qMsg, ActorRef.noSender()); 141 + actorSystem.tell(qMsg);
146 Mockito.verify(tbMsgCallback, Mockito.timeout(3000)).onSuccess(); 142 Mockito.verify(tbMsgCallback, Mockito.timeout(3000)).onSuccess();
147 143
148 144
@@ -13,8 +13,6 @@ @@ -13,8 +13,6 @@
13 <logger name="org.apache.cassandra" level="WARN"/> 13 <logger name="org.apache.cassandra" level="WARN"/>
14 <logger name="org.cassandraunit" level="INFO"/> 14 <logger name="org.cassandraunit" level="INFO"/>
15 15
16 - <logger name="akka" level="INFO" />  
17 -  
18 <root level="WARN"> 16 <root level="WARN">
19 <appender-ref ref="console"/> 17 <appender-ref ref="console"/>
20 </root> 18 </root>
  1 +<!--
  2 +
  3 + Copyright © 2016-2020 The Thingsboard Authors
  4 +
  5 + Licensed under the Apache License, Version 2.0 (the "License");
  6 + you may not use this file except in compliance with the License.
  7 + You may obtain a copy of the License at
  8 +
  9 + http://www.apache.org/licenses/LICENSE-2.0
  10 +
  11 + Unless required by applicable law or agreed to in writing, software
  12 + distributed under the License is distributed on an "AS IS" BASIS,
  13 + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14 + See the License for the specific language governing permissions and
  15 + limitations under the License.
  16 +
  17 +-->
  18 +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  19 + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  20 + <modelVersion>4.0.0</modelVersion>
  21 + <parent>
  22 + <groupId>org.thingsboard</groupId>
  23 + <version>2.5.3-SNAPSHOT</version>
  24 + <artifactId>common</artifactId>
  25 + </parent>
  26 + <groupId>org.thingsboard.common</groupId>
  27 + <artifactId>actor</artifactId>
  28 + <packaging>jar</packaging>
  29 +
  30 + <name>Thingsboard Actor system</name>
  31 + <url>https://thingsboard.io</url>
  32 +
  33 + <properties>
  34 + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  35 + <main.dir>${basedir}/../..</main.dir>
  36 + </properties>
  37 +
  38 + <dependencies>
  39 + <dependency>
  40 + <groupId>org.thingsboard.common</groupId>
  41 + <artifactId>util</artifactId>
  42 + </dependency>
  43 + <dependency>
  44 + <groupId>org.thingsboard.common</groupId>
  45 + <artifactId>message</artifactId>
  46 + </dependency>
  47 + <dependency>
  48 + <groupId>org.slf4j</groupId>
  49 + <artifactId>slf4j-api</artifactId>
  50 + </dependency>
  51 + <dependency>
  52 + <groupId>org.slf4j</groupId>
  53 + <artifactId>log4j-over-slf4j</artifactId>
  54 + </dependency>
  55 + <dependency>
  56 + <groupId>ch.qos.logback</groupId>
  57 + <artifactId>logback-core</artifactId>
  58 + </dependency>
  59 + <dependency>
  60 + <groupId>ch.qos.logback</groupId>
  61 + <artifactId>logback-classic</artifactId>
  62 + </dependency>
  63 + <dependency>
  64 + <groupId>junit</groupId>
  65 + <artifactId>junit</artifactId>
  66 + <scope>test</scope>
  67 + </dependency>
  68 + <dependency>
  69 + <groupId>org.mockito</groupId>
  70 + <artifactId>mockito-all</artifactId>
  71 + <scope>test</scope>
  72 + </dependency>
  73 + </dependencies>
  74 +
  75 +</project>
  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;
  17 +
  18 +import lombok.Getter;
  19 +
  20 +public abstract class AbstractTbActor implements TbActor {
  21 +
  22 + @Getter
  23 + protected TbActorCtx ctx;
  24 +
  25 + @Override
  26 + public void init(TbActorCtx ctx) throws TbActorException {
  27 + this.ctx = ctx;
  28 + }
  29 +
  30 + @Override
  31 + public TbActorRef getActorRef() {
  32 + return ctx;
  33 + }
  34 +}
  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;
  17 +
  18 +import lombok.Data;
  19 +import lombok.Getter;
  20 +import lombok.extern.slf4j.Slf4j;
  21 +import org.thingsboard.common.util.ThingsBoardThreadFactory;
  22 +import org.thingsboard.server.common.msg.TbActorMsg;
  23 +
  24 +import java.util.Collections;
  25 +import java.util.List;
  26 +import java.util.Set;
  27 +import java.util.concurrent.ConcurrentHashMap;
  28 +import java.util.concurrent.ConcurrentMap;
  29 +import java.util.concurrent.ExecutorService;
  30 +import java.util.concurrent.Executors;
  31 +import java.util.concurrent.ScheduledExecutorService;
  32 +import java.util.concurrent.TimeUnit;
  33 +import java.util.concurrent.locks.Lock;
  34 +import java.util.concurrent.locks.ReentrantLock;
  35 +import java.util.function.Predicate;
  36 +import java.util.stream.Collectors;
  37 +
  38 +@Slf4j
  39 +@Data
  40 +public class DefaultTbActorSystem implements TbActorSystem {
  41 +
  42 + private final ConcurrentMap<String, Dispatcher> dispatchers = new ConcurrentHashMap<>();
  43 + private final ConcurrentMap<TbActorId, TbActorMailbox> actors = new ConcurrentHashMap<>();
  44 + private final ConcurrentMap<TbActorId, ReentrantLock> actorCreationLocks = new ConcurrentHashMap<>();
  45 + private final ConcurrentMap<TbActorId, Set<TbActorId>> parentChildMap = new ConcurrentHashMap<>();
  46 +
  47 + @Getter
  48 + private final TbActorSystemSettings settings;
  49 + @Getter
  50 + private final ScheduledExecutorService scheduler;
  51 +
  52 + public DefaultTbActorSystem(TbActorSystemSettings settings) {
  53 + this.settings = settings;
  54 + this.scheduler = Executors.newScheduledThreadPool(settings.getSchedulerPoolSize(), ThingsBoardThreadFactory.forName("actor-system-scheduler"));
  55 + }
  56 +
  57 + @Override
  58 + public void createDispatcher(String dispatcherId, ExecutorService executor) {
  59 + Dispatcher current = dispatchers.putIfAbsent(dispatcherId, new Dispatcher(dispatcherId, executor));
  60 + if (current != null) {
  61 + throw new RuntimeException("Dispatcher with id [" + dispatcherId + "] is already registered!");
  62 + }
  63 + }
  64 +
  65 + @Override
  66 + public void destroyDispatcher(String dispatcherId) {
  67 + Dispatcher dispatcher = dispatchers.remove(dispatcherId);
  68 + if (dispatcher != null) {
  69 + dispatcher.getExecutor().shutdownNow();
  70 + } else {
  71 + throw new RuntimeException("Dispatcher with id [" + dispatcherId + "] is not registered!");
  72 + }
  73 + }
  74 +
  75 + @Override
  76 + public TbActorRef getActor(TbActorId actorId) {
  77 + return actors.get(actorId);
  78 + }
  79 +
  80 + @Override
  81 + public TbActorRef createRootActor(String dispatcherId, TbActorCreator creator) {
  82 + return createActor(dispatcherId, creator, null);
  83 + }
  84 +
  85 + @Override
  86 + public TbActorRef createChildActor(String dispatcherId, TbActorCreator creator, TbActorId parent) {
  87 + return createActor(dispatcherId, creator, parent);
  88 + }
  89 +
  90 + private TbActorRef createActor(String dispatcherId, TbActorCreator creator, TbActorId parent) {
  91 + Dispatcher dispatcher = dispatchers.get(dispatcherId);
  92 + if (dispatcher == null) {
  93 + log.warn("Dispatcher with id [{}] is not registered!", dispatcherId);
  94 + throw new RuntimeException("Dispatcher with id [" + dispatcherId + "] is not registered!");
  95 + }
  96 +
  97 + TbActorId actorId = creator.createActorId();
  98 + TbActorMailbox actorMailbox = actors.get(actorId);
  99 + if (actorMailbox != null) {
  100 + log.debug("Actor with id [{}] is already registered!", actorId);
  101 + } else {
  102 + Lock actorCreationLock = actorCreationLocks.computeIfAbsent(actorId, id -> new ReentrantLock());
  103 + actorCreationLock.lock();
  104 + try {
  105 + actorMailbox = actors.get(actorId);
  106 + if (actorMailbox == null) {
  107 + log.debug("Creating actor with id [{}]!", actorId);
  108 + TbActor actor = creator.createActor();
  109 + TbActorRef parentRef = null;
  110 + if (parent != null) {
  111 + parentRef = getActor(parent);
  112 + if (parentRef == null) {
  113 + throw new TbActorNotRegisteredException(parent, "Parent Actor with id [" + parent + "] is not registered!");
  114 + }
  115 + }
  116 + TbActorMailbox mailbox = new TbActorMailbox(this, settings, actorId, parentRef, actor, dispatcher);
  117 + actors.put(actorId, mailbox);
  118 + mailbox.initActor();
  119 + actorMailbox = mailbox;
  120 + if (parent != null) {
  121 + parentChildMap.computeIfAbsent(parent, id -> ConcurrentHashMap.newKeySet()).add(actorId);
  122 + }
  123 + } else {
  124 + log.debug("Actor with id [{}] is already registered!", actorId);
  125 + }
  126 + } finally {
  127 + actorCreationLock.unlock();
  128 + actorCreationLocks.remove(actorId);
  129 + }
  130 + }
  131 + return actorMailbox;
  132 + }
  133 +
  134 + @Override
  135 + public void tellWithHighPriority(TbActorId target, TbActorMsg actorMsg) {
  136 + tell(target, actorMsg, true);
  137 + }
  138 +
  139 + @Override
  140 + public void tell(TbActorId target, TbActorMsg actorMsg) {
  141 + tell(target, actorMsg, false);
  142 + }
  143 +
  144 + private void tell(TbActorId target, TbActorMsg actorMsg, boolean highPriority) {
  145 + TbActorMailbox mailbox = actors.get(target);
  146 + if (mailbox == null) {
  147 + throw new TbActorNotRegisteredException(target, "Actor with id [" + target + "] is not registered!");
  148 + }
  149 + if (highPriority) {
  150 + mailbox.tellWithHighPriority(actorMsg);
  151 + } else {
  152 + mailbox.tell(actorMsg);
  153 + }
  154 + }
  155 +
  156 +
  157 + @Override
  158 + public void broadcastToChildren(TbActorId parent, TbActorMsg msg) {
  159 + broadcastToChildren(parent, id -> true, msg);
  160 + }
  161 +
  162 + @Override
  163 + public void broadcastToChildren(TbActorId parent, Predicate<TbActorId> childFilter, TbActorMsg msg) {
  164 + Set<TbActorId> children = parentChildMap.get(parent);
  165 + if (children != null) {
  166 + children.stream().filter(childFilter).forEach(id -> tell(id, msg));
  167 + }
  168 + }
  169 +
  170 + @Override
  171 + public List<TbActorId> filterChildren(TbActorId parent, Predicate<TbActorId> childFilter) {
  172 + Set<TbActorId> children = parentChildMap.get(parent);
  173 + if (children != null) {
  174 + return children.stream().filter(childFilter).collect(Collectors.toList());
  175 + } else {
  176 + return Collections.emptyList();
  177 + }
  178 + }
  179 +
  180 + @Override
  181 + public void stop(TbActorRef actorRef) {
  182 + stop(actorRef.getActorId());
  183 + }
  184 +
  185 + @Override
  186 + public void stop(TbActorId actorId) {
  187 + Set<TbActorId> children = parentChildMap.remove(actorId);
  188 + if (children != null) {
  189 + for (TbActorId child : children) {
  190 + stop(child);
  191 + }
  192 + }
  193 + TbActorMailbox mailbox = actors.remove(actorId);
  194 + if (mailbox != null) {
  195 + mailbox.destroy();
  196 + }
  197 + }
  198 +
  199 + @Override
  200 + public void stop() {
  201 + dispatchers.values().forEach(dispatcher -> {
  202 + dispatcher.getExecutor().shutdown();
  203 + try {
  204 + dispatcher.getExecutor().awaitTermination(3, TimeUnit.SECONDS);
  205 + } catch (InterruptedException e) {
  206 + log.warn("[{}] Failed to stop dispatcher", dispatcher.getDispatcherId(), e);
  207 + }
  208 + });
  209 + if (scheduler != null) {
  210 + scheduler.shutdownNow();
  211 + }
  212 + actors.clear();
  213 + }
  214 +
  215 +}
  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;
  17 +
  18 +import lombok.Data;
  19 +
  20 +import java.util.concurrent.ExecutorService;
  21 +
  22 +@Data
  23 +class Dispatcher {
  24 +
  25 + private final String dispatcherId;
  26 + private final ExecutorService executor;
  27 +
  28 +}
  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;
  17 +
  18 +import lombok.Getter;
  19 +import lombok.ToString;
  20 +
  21 +@ToString
  22 +public class InitFailureStrategy {
  23 +
  24 + @Getter
  25 + private boolean stop;
  26 + @Getter
  27 + private long retryDelay;
  28 +
  29 + private InitFailureStrategy(boolean stop, long retryDelay) {
  30 + this.stop = stop;
  31 + this.retryDelay = retryDelay;
  32 + }
  33 +
  34 + public static InitFailureStrategy retryImmediately() {
  35 + return new InitFailureStrategy(false, 0);
  36 + }
  37 +
  38 + public static InitFailureStrategy retryWithDelay(long ms) {
  39 + return new InitFailureStrategy(false, ms);
  40 + }
  41 +
  42 + public static InitFailureStrategy stop() {
  43 + return new InitFailureStrategy(true, 0);
  44 + }
  45 +}
  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;
  17 +
  18 +import lombok.Getter;
  19 +import lombok.ToString;
  20 +
  21 +@ToString
  22 +public class ProcessFailureStrategy {
  23 +
  24 + @Getter
  25 + private boolean stop;
  26 +
  27 + private ProcessFailureStrategy(boolean stop) {
  28 + this.stop = stop;
  29 + }
  30 +
  31 + public static ProcessFailureStrategy stop() {
  32 + return new ProcessFailureStrategy(true);
  33 + }
  34 +
  35 + public static ProcessFailureStrategy resume() {
  36 + return new ProcessFailureStrategy(false);
  37 + }
  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.actors;
  17 +
  18 +import org.thingsboard.server.common.msg.TbActorMsg;
  19 +
  20 +public interface TbActor {
  21 +
  22 + boolean process(TbActorMsg msg);
  23 +
  24 + TbActorRef getActorRef();
  25 +
  26 + default void init(TbActorCtx ctx) throws TbActorException {
  27 + }
  28 +
  29 + default void destroy() throws TbActorException {
  30 + }
  31 +
  32 + default InitFailureStrategy onInitFailure(int attempt, Throwable t) {
  33 + return InitFailureStrategy.retryWithDelay(5000 * attempt);
  34 + }
  35 +
  36 + default ProcessFailureStrategy onProcessFailure(Throwable t) {
  37 + if (t instanceof Error) {
  38 + return ProcessFailureStrategy.stop();
  39 + } else {
  40 + return ProcessFailureStrategy.resume();
  41 + }
  42 + }
  43 +}
  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;
  17 +
  18 +public interface TbActorCreator {
  19 +
  20 + TbActorId createActorId();
  21 +
  22 + TbActor createActor();
  23 +
  24 +}
  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;
  17 +
  18 +import org.thingsboard.server.common.msg.TbActorMsg;
  19 +
  20 +import java.util.List;
  21 +import java.util.function.Predicate;
  22 +import java.util.function.Supplier;
  23 +
  24 +public interface TbActorCtx extends TbActorRef {
  25 +
  26 + TbActorId getSelf();
  27 +
  28 + TbActorRef getParentRef();
  29 +
  30 + void tell(TbActorId target, TbActorMsg msg);
  31 +
  32 + void stop(TbActorId target);
  33 +
  34 + TbActorRef getOrCreateChildActor(TbActorId actorId, Supplier<String> dispatcher, Supplier<TbActorCreator> creator);
  35 +
  36 + void broadcastToChildren(TbActorMsg msg);
  37 +
  38 + void broadcastToChildren(TbActorMsg msg, Predicate<TbActorId> childFilter);
  39 +
  40 + List<TbActorId> filterChildren(Predicate<TbActorId> childFilter);
  41 +}
  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;
  17 +
  18 +public class TbActorException extends Exception {
  19 +
  20 + public TbActorException(String message, Throwable cause) {
  21 + super(message, cause);
  22 + }
  23 +}
  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;
  17 +
  18 +public interface TbActorId {
  19 +
  20 +}
  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;
  17 +
  18 +import lombok.Data;
  19 +import lombok.extern.slf4j.Slf4j;
  20 +import org.thingsboard.server.common.msg.TbActorMsg;
  21 +
  22 +import java.util.List;
  23 +import java.util.concurrent.ConcurrentLinkedQueue;
  24 +import java.util.concurrent.TimeUnit;
  25 +import java.util.concurrent.atomic.AtomicBoolean;
  26 +import java.util.function.Predicate;
  27 +import java.util.function.Supplier;
  28 +
  29 +@Slf4j
  30 +@Data
  31 +public final class TbActorMailbox implements TbActorCtx {
  32 + private static final boolean HIGH_PRIORITY = true;
  33 + private static final boolean NORMAL_PRIORITY = false;
  34 +
  35 + private static final boolean FREE = false;
  36 + private static final boolean BUSY = true;
  37 +
  38 + private static final boolean NOT_READY = false;
  39 + private static final boolean READY = true;
  40 +
  41 + private final TbActorSystem system;
  42 + private final TbActorSystemSettings settings;
  43 + private final TbActorId selfId;
  44 + private final TbActorRef parentRef;
  45 + private final TbActor actor;
  46 + private final Dispatcher dispatcher;
  47 + private final ConcurrentLinkedQueue<TbActorMsg> highPriorityMsgs = new ConcurrentLinkedQueue<>();
  48 + private final ConcurrentLinkedQueue<TbActorMsg> normalPriorityMsgs = new ConcurrentLinkedQueue<>();
  49 + private final AtomicBoolean busy = new AtomicBoolean(FREE);
  50 + private final AtomicBoolean ready = new AtomicBoolean(NOT_READY);
  51 + private final AtomicBoolean destroyInProgress = new AtomicBoolean();
  52 +
  53 + public void initActor() {
  54 + dispatcher.getExecutor().execute(() -> tryInit(1));
  55 + }
  56 +
  57 + private void tryInit(int attempt) {
  58 + try {
  59 + log.debug("[{}] Trying to init actor, attempt: {}", selfId, attempt);
  60 + if (!destroyInProgress.get()) {
  61 + actor.init(this);
  62 + if (!destroyInProgress.get()) {
  63 + ready.set(READY);
  64 + tryProcessQueue(false);
  65 + }
  66 + }
  67 + } catch (Throwable t) {
  68 + log.debug("[{}] Failed to init actor, attempt: {}", selfId, attempt, t);
  69 + int attemptIdx = attempt + 1;
  70 + InitFailureStrategy strategy = actor.onInitFailure(attempt, t);
  71 + if (strategy.isStop() || (settings.getMaxActorInitAttempts() > 0 && attemptIdx > settings.getMaxActorInitAttempts())) {
  72 + log.info("[{}] Failed to init actor, attempt {}, going to stop attempts.", selfId, attempt, t);
  73 + system.stop(selfId);
  74 + } else if (strategy.getRetryDelay() > 0) {
  75 + log.info("[{}] Failed to init actor, attempt {}, going to retry in attempts in {}ms", selfId, attempt, strategy.getRetryDelay());
  76 + log.debug("[{}] Error", selfId, t);
  77 + system.getScheduler().schedule(() -> dispatcher.getExecutor().execute(() -> tryInit(attemptIdx)), strategy.getRetryDelay(), TimeUnit.MILLISECONDS);
  78 + } else {
  79 + log.info("[{}] Failed to init actor, attempt {}, going to retry immediately", selfId, attempt);
  80 + log.debug("[{}] Error", selfId, t);
  81 + dispatcher.getExecutor().execute(() -> tryInit(attemptIdx));
  82 + }
  83 + }
  84 + }
  85 +
  86 + private void enqueue(TbActorMsg msg, boolean highPriority) {
  87 + if (highPriority) {
  88 + highPriorityMsgs.add(msg);
  89 + } else {
  90 + normalPriorityMsgs.add(msg);
  91 + }
  92 + tryProcessQueue(true);
  93 + }
  94 +
  95 + private void tryProcessQueue(boolean newMsg) {
  96 + if (ready.get() == READY) {
  97 + if (newMsg || !highPriorityMsgs.isEmpty() || !normalPriorityMsgs.isEmpty()) {
  98 + if (busy.compareAndSet(FREE, BUSY)) {
  99 + dispatcher.getExecutor().execute(this::processMailbox);
  100 + } else {
  101 + log.trace("[{}] MessageBox is busy, new msg: {}", selfId, newMsg);
  102 + }
  103 + } else {
  104 + log.trace("[{}] MessageBox is empty, new msg: {}", selfId, newMsg);
  105 + }
  106 + } else {
  107 + log.trace("[{}] MessageBox is not ready, new msg: {}", selfId, newMsg);
  108 + }
  109 + }
  110 +
  111 + private void processMailbox() {
  112 + boolean noMoreElements = false;
  113 + for (int i = 0; i < settings.getActorThroughput(); i++) {
  114 + TbActorMsg msg = highPriorityMsgs.poll();
  115 + if (msg == null) {
  116 + msg = normalPriorityMsgs.poll();
  117 + }
  118 + if (msg != null) {
  119 + try {
  120 + log.debug("[{}] Going to process message: {}", selfId, msg);
  121 + actor.process(msg);
  122 + } catch (Throwable t) {
  123 + log.debug("[{}] Failed to process message: {}", selfId, msg, t);
  124 + ProcessFailureStrategy strategy = actor.onProcessFailure(t);
  125 + if (strategy.isStop()) {
  126 + system.stop(selfId);
  127 + }
  128 + }
  129 + } else {
  130 + noMoreElements = true;
  131 + break;
  132 + }
  133 + }
  134 + if (noMoreElements) {
  135 + busy.set(FREE);
  136 + dispatcher.getExecutor().execute(() -> tryProcessQueue(false));
  137 + } else {
  138 + dispatcher.getExecutor().execute(this::processMailbox);
  139 + }
  140 + }
  141 +
  142 + @Override
  143 + public TbActorId getSelf() {
  144 + return selfId;
  145 + }
  146 +
  147 + @Override
  148 + public void tell(TbActorId target, TbActorMsg actorMsg) {
  149 + system.tell(target, actorMsg);
  150 + }
  151 +
  152 + @Override
  153 + public void broadcastToChildren(TbActorMsg msg) {
  154 + system.broadcastToChildren(selfId, msg);
  155 + }
  156 +
  157 + @Override
  158 + public void broadcastToChildren(TbActorMsg msg, Predicate<TbActorId> childFilter) {
  159 + system.broadcastToChildren(selfId, childFilter, msg);
  160 + }
  161 +
  162 + @Override
  163 + public List<TbActorId> filterChildren(Predicate<TbActorId> childFilter) {
  164 + return system.filterChildren(selfId, childFilter);
  165 + }
  166 +
  167 + @Override
  168 + public void stop(TbActorId target) {
  169 + system.stop(target);
  170 + }
  171 +
  172 + @Override
  173 + public TbActorRef getOrCreateChildActor(TbActorId actorId, Supplier<String> dispatcher, Supplier<TbActorCreator> creator) {
  174 + TbActorRef actorRef = system.getActor(actorId);
  175 + if (actorRef == null) {
  176 + return system.createChildActor(dispatcher.get(), creator.get(), selfId);
  177 + } else {
  178 + return actorRef;
  179 + }
  180 + }
  181 +
  182 + public void destroy() {
  183 + destroyInProgress.set(true);
  184 + dispatcher.getExecutor().execute(() -> {
  185 + try {
  186 + ready.set(NOT_READY);
  187 + actor.destroy();
  188 + } catch (Throwable t) {
  189 + log.warn("[{}] Failed to destroy actor: {}", selfId, t);
  190 + }
  191 + });
  192 + }
  193 +
  194 + @Override
  195 + public TbActorId getActorId() {
  196 + return selfId;
  197 + }
  198 +
  199 + @Override
  200 + public void tell(TbActorMsg actorMsg) {
  201 + enqueue(actorMsg, NORMAL_PRIORITY);
  202 + }
  203 +
  204 + @Override
  205 + public void tellWithHighPriority(TbActorMsg actorMsg) {
  206 + enqueue(actorMsg, HIGH_PRIORITY);
  207 + }
  208 +
  209 +}
  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;
  17 +
  18 +import lombok.Getter;
  19 +
  20 +public class TbActorNotRegisteredException extends RuntimeException {
  21 +
  22 + @Getter
  23 + private TbActorId target;
  24 +
  25 + public TbActorNotRegisteredException(TbActorId target, String message) {
  26 + super(message);
  27 + this.target = target;
  28 + }
  29 +}
  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;
  17 +
  18 +import org.thingsboard.server.common.msg.TbActorMsg;
  19 +
  20 +public interface TbActorRef {
  21 +
  22 + TbActorId getActorId();
  23 +
  24 + void tell(TbActorMsg actorMsg);
  25 +
  26 + void tellWithHighPriority(TbActorMsg actorMsg);
  27 +
  28 +}
  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;
  17 +
  18 +import org.thingsboard.server.common.msg.TbActorMsg;
  19 +
  20 +import java.util.List;
  21 +import java.util.concurrent.ExecutorService;
  22 +import java.util.concurrent.ScheduledExecutorService;
  23 +import java.util.function.Predicate;
  24 +
  25 +public interface TbActorSystem {
  26 +
  27 + ScheduledExecutorService getScheduler();
  28 +
  29 + void createDispatcher(String dispatcherId, ExecutorService executor);
  30 +
  31 + void destroyDispatcher(String dispatcherId);
  32 +
  33 + TbActorRef getActor(TbActorId actorId);
  34 +
  35 + TbActorRef createRootActor(String dispatcherId, TbActorCreator creator);
  36 +
  37 + TbActorRef createChildActor(String dispatcherId, TbActorCreator creator, TbActorId parent);
  38 +
  39 + void tell(TbActorId target, TbActorMsg actorMsg);
  40 +
  41 + void tellWithHighPriority(TbActorId target, TbActorMsg actorMsg);
  42 +
  43 + void stop(TbActorRef actorRef);
  44 +
  45 + void stop(TbActorId actorId);
  46 +
  47 + void stop();
  48 +
  49 + void broadcastToChildren(TbActorId parent, TbActorMsg msg);
  50 +
  51 + void broadcastToChildren(TbActorId parent, Predicate<TbActorId> childFilter, TbActorMsg msg);
  52 +
  53 + List<TbActorId> filterChildren(TbActorId parent, Predicate<TbActorId> childFilter);
  54 +}
  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;
  17 +
  18 +import lombok.Data;
  19 +
  20 +@Data
  21 +public class TbActorSystemSettings {
  22 +
  23 + private final int actorThroughput;
  24 + private final int schedulerPoolSize;
  25 + private final int maxActorInitAttempts;
  26 +
  27 +}
  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;
  17 +
  18 +import lombok.Getter;
  19 +import org.thingsboard.server.common.data.id.EntityId;
  20 +
  21 +import java.util.Objects;
  22 +
  23 +public class TbEntityActorId implements TbActorId {
  24 +
  25 + @Getter
  26 + private final EntityId entityId;
  27 +
  28 + public TbEntityActorId(EntityId entityId) {
  29 + this.entityId = entityId;
  30 + }
  31 +
  32 + @Override
  33 + public String toString() {
  34 + return entityId.getEntityType() + "|" + entityId.getId();
  35 + }
  36 +
  37 + @Override
  38 + public boolean equals(Object o) {
  39 + if (this == o) return true;
  40 + if (o == null || getClass() != o.getClass()) return false;
  41 + TbEntityActorId that = (TbEntityActorId) o;
  42 + return entityId.equals(that.entityId);
  43 + }
  44 +
  45 + @Override
  46 + public int hashCode() {
  47 + return Objects.hash(entityId);
  48 + }
  49 +}
  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;
  17 +
  18 +import java.util.Objects;
  19 +
  20 +public class TbStringActorId implements TbActorId {
  21 +
  22 + private final String id;
  23 +
  24 + public TbStringActorId(String id) {
  25 + this.id = id;
  26 + }
  27 +
  28 + @Override
  29 + public String toString() {
  30 + return id;
  31 + }
  32 +
  33 + @Override
  34 + public boolean equals(Object o) {
  35 + if (this == o) return true;
  36 + if (o == null || getClass() != o.getClass()) return false;
  37 + TbStringActorId that = (TbStringActorId) o;
  38 + return id.equals(that.id);
  39 + }
  40 +
  41 + @Override
  42 + public int hashCode() {
  43 + return Objects.hash(id);
  44 + }
  45 +}
  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;
  17 +
  18 +import lombok.extern.slf4j.Slf4j;
  19 +import org.junit.After;
  20 +import org.junit.Assert;
  21 +import org.junit.Before;
  22 +import org.junit.Test;
  23 +import org.junit.runner.RunWith;
  24 +import org.mockito.runners.MockitoJUnitRunner;
  25 +import org.thingsboard.server.common.data.id.DeviceId;
  26 +
  27 +import java.util.ArrayList;
  28 +import java.util.List;
  29 +import java.util.Random;
  30 +import java.util.UUID;
  31 +import java.util.concurrent.CountDownLatch;
  32 +import java.util.concurrent.ExecutorService;
  33 +import java.util.concurrent.Executors;
  34 +import java.util.concurrent.TimeUnit;
  35 +import java.util.concurrent.atomic.AtomicInteger;
  36 +import java.util.concurrent.atomic.AtomicLong;
  37 +
  38 +@Slf4j
  39 +@RunWith(MockitoJUnitRunner.class)
  40 +public class ActorSystemTest {
  41 +
  42 + public static final String ROOT_DISPATCHER = "root-dispatcher";
  43 + private static final int _100K = 100 * 1024;
  44 +
  45 + private volatile TbActorSystem actorSystem;
  46 + private volatile ExecutorService submitPool;
  47 + private int parallelism;
  48 +
  49 + @Before
  50 + public void initActorSystem() {
  51 + int cores = Runtime.getRuntime().availableProcessors();
  52 + parallelism = Math.max(2, cores / 2);
  53 + TbActorSystemSettings settings = new TbActorSystemSettings(5, parallelism, 42);
  54 + actorSystem = new DefaultTbActorSystem(settings);
  55 + submitPool = Executors.newWorkStealingPool(parallelism);
  56 + }
  57 +
  58 + @After
  59 + public void shutdownActorSystem() {
  60 + actorSystem.stop();
  61 + submitPool.shutdownNow();
  62 + }
  63 +
  64 + @Test
  65 + public void test1actorsAnd100KMessages() throws InterruptedException {
  66 + actorSystem.createDispatcher(ROOT_DISPATCHER, Executors.newWorkStealingPool(parallelism));
  67 + testActorsAndMessages(1, _100K, 1);
  68 + }
  69 +
  70 + @Test
  71 + public void test10actorsAnd100KMessages() throws InterruptedException {
  72 + actorSystem.createDispatcher(ROOT_DISPATCHER, Executors.newWorkStealingPool(parallelism));
  73 + testActorsAndMessages(10, _100K, 1);
  74 + }
  75 +
  76 + @Test
  77 + public void test100KActorsAnd1Messages5timesSingleThread() throws InterruptedException {
  78 + actorSystem.createDispatcher(ROOT_DISPATCHER, Executors.newSingleThreadExecutor());
  79 + testActorsAndMessages(_100K, 1, 5);
  80 + }
  81 +
  82 + @Test
  83 + public void test100KActorsAnd1Messages5times() throws InterruptedException {
  84 + actorSystem.createDispatcher(ROOT_DISPATCHER, Executors.newWorkStealingPool(parallelism));
  85 + testActorsAndMessages(_100K, 1, 5);
  86 + }
  87 +
  88 + @Test
  89 + public void test100KActorsAnd10Messages() throws InterruptedException {
  90 + actorSystem.createDispatcher(ROOT_DISPATCHER, Executors.newWorkStealingPool(parallelism));
  91 + testActorsAndMessages(_100K, 10, 1);
  92 + }
  93 +
  94 + @Test
  95 + public void test1KActorsAnd1KMessages() throws InterruptedException {
  96 + actorSystem.createDispatcher(ROOT_DISPATCHER, Executors.newWorkStealingPool(parallelism));
  97 + testActorsAndMessages(1000, 1000, 10);
  98 + }
  99 +
  100 + @Test
  101 + public void testNoMessagesAfterDestroy() throws InterruptedException {
  102 + actorSystem.createDispatcher(ROOT_DISPATCHER, Executors.newWorkStealingPool(parallelism));
  103 + ActorTestCtx testCtx1 = getActorTestCtx(1);
  104 + ActorTestCtx testCtx2 = getActorTestCtx(1);
  105 +
  106 + TbActorRef actorId1 = actorSystem.createRootActor(ROOT_DISPATCHER, new SlowInitActor.SlowInitActorCreator(
  107 + new TbEntityActorId(new DeviceId(UUID.randomUUID())), testCtx1));
  108 + TbActorRef actorId2 = actorSystem.createRootActor(ROOT_DISPATCHER, new SlowInitActor.SlowInitActorCreator(
  109 + new TbEntityActorId(new DeviceId(UUID.randomUUID())), testCtx2));
  110 +
  111 + actorId1.tell(new IntTbActorMsg(42));
  112 + actorId2.tell(new IntTbActorMsg(42));
  113 + actorSystem.stop(actorId1);
  114 +
  115 + Assert.assertTrue(testCtx2.getLatch().await(1, TimeUnit.SECONDS));
  116 + Assert.assertFalse(testCtx1.getLatch().await(1, TimeUnit.SECONDS));
  117 + }
  118 +
  119 + @Test
  120 + public void testOneActorCreated() throws InterruptedException {
  121 + actorSystem.createDispatcher(ROOT_DISPATCHER, Executors.newWorkStealingPool(parallelism));
  122 + ActorTestCtx testCtx1 = getActorTestCtx(1);
  123 + ActorTestCtx testCtx2 = getActorTestCtx(1);
  124 + TbActorId actorId = new TbEntityActorId(new DeviceId(UUID.randomUUID()));
  125 + submitPool.submit(() -> actorSystem.createRootActor(ROOT_DISPATCHER, new SlowCreateActor.SlowCreateActorCreator(actorId, testCtx1)));
  126 + submitPool.submit(() -> actorSystem.createRootActor(ROOT_DISPATCHER, new SlowCreateActor.SlowCreateActorCreator(actorId, testCtx2)));
  127 +
  128 + Thread.sleep(1000);
  129 + actorSystem.tell(actorId, new IntTbActorMsg(42));
  130 +
  131 + Assert.assertTrue(testCtx1.getLatch().await(1, TimeUnit.SECONDS));
  132 + Assert.assertFalse(testCtx2.getLatch().await(1, TimeUnit.SECONDS));
  133 + }
  134 +
  135 + @Test
  136 + public void testActorCreatorCalledOnce() throws InterruptedException {
  137 + actorSystem.createDispatcher(ROOT_DISPATCHER, Executors.newWorkStealingPool(parallelism));
  138 + ActorTestCtx testCtx = getActorTestCtx(1);
  139 + TbActorId actorId = new TbEntityActorId(new DeviceId(UUID.randomUUID()));
  140 + for (int i = 0; i < 1000; i++) {
  141 + submitPool.submit(() -> actorSystem.createRootActor(ROOT_DISPATCHER, new SlowCreateActor.SlowCreateActorCreator(actorId, testCtx)));
  142 + }
  143 + Thread.sleep(1000);
  144 + actorSystem.tell(actorId, new IntTbActorMsg(42));
  145 +
  146 + Assert.assertTrue(testCtx.getLatch().await(1, TimeUnit.SECONDS));
  147 + //One for creation and one for message
  148 + Assert.assertEquals(2, testCtx.getInvocationCount().get());
  149 + }
  150 +
  151 + @Test
  152 + public void testFailedInit() throws InterruptedException {
  153 + actorSystem.createDispatcher(ROOT_DISPATCHER, Executors.newWorkStealingPool(parallelism));
  154 + ActorTestCtx testCtx1 = getActorTestCtx(1);
  155 + ActorTestCtx testCtx2 = getActorTestCtx(1);
  156 +
  157 + TbActorRef actorId1 = actorSystem.createRootActor(ROOT_DISPATCHER, new FailedToInitActor.FailedToInitActorCreator(
  158 + new TbEntityActorId(new DeviceId(UUID.randomUUID())), testCtx1, 1, 3000));
  159 + TbActorRef actorId2 = actorSystem.createRootActor(ROOT_DISPATCHER, new FailedToInitActor.FailedToInitActorCreator(
  160 + new TbEntityActorId(new DeviceId(UUID.randomUUID())), testCtx2, 2, 1));
  161 +
  162 + actorId1.tell(new IntTbActorMsg(42));
  163 + actorId2.tell(new IntTbActorMsg(42));
  164 +
  165 + Assert.assertFalse(testCtx1.getLatch().await(2, TimeUnit.SECONDS));
  166 + Assert.assertTrue(testCtx2.getLatch().await(1, TimeUnit.SECONDS));
  167 + Assert.assertTrue(testCtx1.getLatch().await(3, TimeUnit.SECONDS));
  168 + }
  169 +
  170 +
  171 + public void testActorsAndMessages(int actorsCount, int msgNumber, int times) throws InterruptedException {
  172 + Random random = new Random();
  173 + int[] randomIntegers = new int[msgNumber];
  174 + long sumTmp = 0;
  175 + for (int i = 0; i < msgNumber; i++) {
  176 + int tmp = random.nextInt();
  177 + randomIntegers[i] = tmp;
  178 + sumTmp += tmp;
  179 + }
  180 + long expected = sumTmp;
  181 +
  182 + List<ActorTestCtx> testCtxes = new ArrayList<>();
  183 +
  184 + List<TbActorRef> actorRefs = new ArrayList<>();
  185 + for (int actorIdx = 0; actorIdx < actorsCount; actorIdx++) {
  186 + ActorTestCtx testCtx = getActorTestCtx(msgNumber);
  187 + actorRefs.add(actorSystem.createRootActor(ROOT_DISPATCHER, new TestRootActor.TestRootActorCreator(
  188 + new TbEntityActorId(new DeviceId(UUID.randomUUID())), testCtx)));
  189 + testCtxes.add(testCtx);
  190 + }
  191 +
  192 + for (int t = 0; t < times; t++) {
  193 + long start = System.nanoTime();
  194 + for (int i = 0; i < msgNumber; i++) {
  195 + int tmp = randomIntegers[i];
  196 + submitPool.execute(() -> actorRefs.forEach(actorId -> actorId.tell(new IntTbActorMsg(tmp))));
  197 + }
  198 + log.info("Submitted all messages");
  199 + testCtxes.forEach(ctx -> {
  200 + try {
  201 + boolean success = ctx.getLatch().await(1, TimeUnit.MINUTES);
  202 + if (!success) {
  203 + log.warn("Failed: {}, {}", ctx.getActual().get(), ctx.getInvocationCount().get());
  204 + }
  205 + Assert.assertTrue(success);
  206 + Assert.assertEquals(expected, ctx.getActual().get());
  207 + Assert.assertEquals(msgNumber, ctx.getInvocationCount().get());
  208 + ctx.clear();
  209 + } catch (InterruptedException e) {
  210 + e.printStackTrace();
  211 + }
  212 + });
  213 + long duration = System.nanoTime() - start;
  214 + log.info("Time spend: {}ns ({} ms)", duration, TimeUnit.NANOSECONDS.toMillis(duration));
  215 + }
  216 + }
  217 +
  218 + private ActorTestCtx getActorTestCtx(int i) {
  219 + CountDownLatch countDownLatch = new CountDownLatch(1);
  220 + AtomicLong actual = new AtomicLong();
  221 + AtomicInteger invocations = new AtomicInteger();
  222 + return new ActorTestCtx(countDownLatch, invocations, i, actual);
  223 + }
  224 +}
  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;
  17 +
  18 +import lombok.AllArgsConstructor;
  19 +import lombok.Data;
  20 +
  21 +import java.util.concurrent.CountDownLatch;
  22 +import java.util.concurrent.atomic.AtomicInteger;
  23 +import java.util.concurrent.atomic.AtomicLong;
  24 +
  25 +@Data
  26 +@AllArgsConstructor
  27 +public class ActorTestCtx {
  28 +
  29 + private volatile CountDownLatch latch;
  30 + private final AtomicInteger invocationCount;
  31 + private final int expectedInvocationCount;
  32 + private final AtomicLong actual;
  33 +
  34 + public void clear() {
  35 + latch = new CountDownLatch(1);
  36 + invocationCount.set(0);
  37 + actual.set(0L);
  38 + }
  39 +}
  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;
  17 +
  18 +import lombok.extern.slf4j.Slf4j;
  19 +
  20 +@Slf4j
  21 +public class FailedToInitActor extends TestRootActor {
  22 +
  23 + int retryAttempts;
  24 + int retryDelay;
  25 + int attempts = 0;
  26 +
  27 + public FailedToInitActor(TbActorId actorId, ActorTestCtx testCtx, int retryAttempts, int retryDelay) {
  28 + super(actorId, testCtx);
  29 + this.retryAttempts = retryAttempts;
  30 + this.retryDelay = retryDelay;
  31 + }
  32 +
  33 + @Override
  34 + public void init(TbActorCtx ctx) throws TbActorException {
  35 + if (attempts < retryAttempts) {
  36 + attempts++;
  37 + throw new TbActorException("Test attempt", new RuntimeException());
  38 + } else {
  39 + super.init(ctx);
  40 + }
  41 + }
  42 +
  43 + @Override
  44 + public InitFailureStrategy onInitFailure(int attempt, Throwable t) {
  45 + return InitFailureStrategy.retryWithDelay(retryDelay);
  46 + }
  47 +
  48 + public static class FailedToInitActorCreator implements TbActorCreator {
  49 +
  50 + private final TbActorId actorId;
  51 + private final ActorTestCtx testCtx;
  52 + private final int retryAttempts;
  53 + private final int retryDelay;
  54 +
  55 + public FailedToInitActorCreator(TbActorId actorId, ActorTestCtx testCtx, int retryAttempts, int retryDelay) {
  56 + this.actorId = actorId;
  57 + this.testCtx = testCtx;
  58 + this.retryAttempts = retryAttempts;
  59 + this.retryDelay = retryDelay;
  60 + }
  61 +
  62 + @Override
  63 + public TbActorId createActorId() {
  64 + return actorId;
  65 + }
  66 +
  67 + @Override
  68 + public TbActor createActor() {
  69 + return new FailedToInitActor(actorId, testCtx, retryAttempts, retryDelay);
  70 + }
  71 + }
  72 +}
  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;
  17 +
  18 +import lombok.Getter;
  19 +import org.thingsboard.server.common.msg.MsgType;
  20 +import org.thingsboard.server.common.msg.TbActorMsg;
  21 +
  22 +public class IntTbActorMsg implements TbActorMsg {
  23 +
  24 + @Getter
  25 + private final int value;
  26 +
  27 + public IntTbActorMsg(int value) {
  28 + this.value = value;
  29 + }
  30 +
  31 + @Override
  32 + public MsgType getMsgType() {
  33 + return MsgType.QUEUE_TO_RULE_ENGINE_MSG;
  34 + }
  35 +}
  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;
  17 +
  18 +import lombok.extern.slf4j.Slf4j;
  19 +
  20 +@Slf4j
  21 +public class SlowCreateActor extends TestRootActor {
  22 +
  23 + public SlowCreateActor(TbActorId actorId, ActorTestCtx testCtx) {
  24 + super(actorId, testCtx);
  25 + try {
  26 + Thread.sleep(500);
  27 + } catch (InterruptedException e) {
  28 + e.printStackTrace();
  29 + }
  30 + testCtx.getInvocationCount().incrementAndGet();
  31 + }
  32 +
  33 + public static class SlowCreateActorCreator implements TbActorCreator {
  34 +
  35 + private final TbActorId actorId;
  36 + private final ActorTestCtx testCtx;
  37 +
  38 + public SlowCreateActorCreator(TbActorId actorId, ActorTestCtx testCtx) {
  39 + this.actorId = actorId;
  40 + this.testCtx = testCtx;
  41 + }
  42 +
  43 + @Override
  44 + public TbActorId createActorId() {
  45 + return actorId;
  46 + }
  47 +
  48 + @Override
  49 + public TbActor createActor() {
  50 + return new SlowCreateActor(actorId, testCtx);
  51 + }
  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.server.actors;
  17 +
  18 +import lombok.extern.slf4j.Slf4j;
  19 +
  20 +@Slf4j
  21 +public class SlowInitActor extends TestRootActor {
  22 +
  23 + public SlowInitActor(TbActorId actorId, ActorTestCtx testCtx) {
  24 + super(actorId, testCtx);
  25 + }
  26 +
  27 + @Override
  28 + public void init(TbActorCtx ctx) throws TbActorException {
  29 + try {
  30 + Thread.sleep(500);
  31 + } catch (InterruptedException e) {
  32 + e.printStackTrace();
  33 + }
  34 + super.init(ctx);
  35 + }
  36 +
  37 + public static class SlowInitActorCreator implements TbActorCreator {
  38 +
  39 + private final TbActorId actorId;
  40 + private final ActorTestCtx testCtx;
  41 +
  42 + public SlowInitActorCreator(TbActorId actorId, ActorTestCtx testCtx) {
  43 + this.actorId = actorId;
  44 + this.testCtx = testCtx;
  45 + }
  46 +
  47 + @Override
  48 + public TbActorId createActorId() {
  49 + return actorId;
  50 + }
  51 +
  52 + @Override
  53 + public TbActor createActor() {
  54 + return new SlowInitActor(actorId, testCtx);
  55 + }
  56 + }
  57 +}
  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;
  17 +
  18 +import lombok.Getter;
  19 +import lombok.extern.slf4j.Slf4j;
  20 +import org.thingsboard.server.common.msg.TbActorMsg;
  21 +
  22 +@Slf4j
  23 +public class TestRootActor extends AbstractTbActor {
  24 +
  25 + @Getter
  26 + private final TbActorId actorId;
  27 + @Getter
  28 + private final ActorTestCtx testCtx;
  29 +
  30 + private boolean initialized;
  31 + private long sum;
  32 + private int count;
  33 +
  34 + public TestRootActor(TbActorId actorId, ActorTestCtx testCtx) {
  35 + this.actorId = actorId;
  36 + this.testCtx = testCtx;
  37 + }
  38 +
  39 + @Override
  40 + public void init(TbActorCtx ctx) throws TbActorException {
  41 + super.init(ctx);
  42 + initialized = true;
  43 + }
  44 +
  45 + @Override
  46 + public boolean process(TbActorMsg msg) {
  47 + if (initialized) {
  48 + int value = ((IntTbActorMsg) msg).getValue();
  49 + sum += value;
  50 + count += 1;
  51 + if (count == testCtx.getExpectedInvocationCount()) {
  52 + testCtx.getActual().set(sum);
  53 + testCtx.getInvocationCount().addAndGet(count);
  54 + sum = 0;
  55 + count = 0;
  56 + testCtx.getLatch().countDown();
  57 + }
  58 + }
  59 + return true;
  60 + }
  61 +
  62 + @Override
  63 + public void destroy() {
  64 +
  65 + }
  66 +
  67 + public static class TestRootActorCreator implements TbActorCreator {
  68 +
  69 + private final TbActorId actorId;
  70 + private final ActorTestCtx testCtx;
  71 +
  72 + public TestRootActorCreator(TbActorId actorId, ActorTestCtx testCtx) {
  73 + this.actorId = actorId;
  74 + this.testCtx = testCtx;
  75 + }
  76 +
  77 + @Override
  78 + public TbActorId createActorId() {
  79 + return actorId;
  80 + }
  81 +
  82 + @Override
  83 + public TbActor createActor() {
  84 + return new TestRootActor(actorId, testCtx);
  85 + }
  86 + }
  87 +}
  1 +<?xml version="1.0" encoding="UTF-8" ?>
  2 +
  3 +<configuration>
  4 + <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
  5 + <encoder>
  6 + <pattern>%d{ISO8601} [%thread] %-5level %logger{36} - %msg%n</pattern>
  7 + </encoder>
  8 + </appender>
  9 +
  10 + <root level="INFO">
  11 + <appender-ref ref="console"/>
  12 + </root>
  13 +
  14 +</configuration>
@@ -20,7 +20,7 @@ @@ -20,7 +20,7 @@
20 <modelVersion>4.0.0</modelVersion> 20 <modelVersion>4.0.0</modelVersion>
21 <parent> 21 <parent>
22 <groupId>org.thingsboard</groupId> 22 <groupId>org.thingsboard</groupId>
23 - <version>2.5.1-SNAPSHOT</version> 23 + <version>2.5.3-SNAPSHOT</version>
24 <artifactId>common</artifactId> 24 <artifactId>common</artifactId>
25 </parent> 25 </parent>
26 <groupId>org.thingsboard.common</groupId> 26 <groupId>org.thingsboard.common</groupId>
@@ -20,7 +20,7 @@ @@ -20,7 +20,7 @@
20 <modelVersion>4.0.0</modelVersion> 20 <modelVersion>4.0.0</modelVersion>
21 <parent> 21 <parent>
22 <groupId>org.thingsboard</groupId> 22 <groupId>org.thingsboard</groupId>
23 - <version>2.5.1-SNAPSHOT</version> 23 + <version>2.5.3-SNAPSHOT</version>
24 <artifactId>common</artifactId> 24 <artifactId>common</artifactId>
25 </parent> 25 </parent>
26 <groupId>org.thingsboard.common</groupId> 26 <groupId>org.thingsboard.common</groupId>
@@ -20,7 +20,7 @@ @@ -20,7 +20,7 @@
20 <modelVersion>4.0.0</modelVersion> 20 <modelVersion>4.0.0</modelVersion>
21 <parent> 21 <parent>
22 <groupId>org.thingsboard</groupId> 22 <groupId>org.thingsboard</groupId>
23 - <version>2.5.1-SNAPSHOT</version> 23 + <version>2.5.3-SNAPSHOT</version>
24 <artifactId>common</artifactId> 24 <artifactId>common</artifactId>
25 </parent> 25 </parent>
26 <groupId>org.thingsboard.common</groupId> 26 <groupId>org.thingsboard.common</groupId>
@@ -20,7 +20,7 @@ @@ -20,7 +20,7 @@
20 <modelVersion>4.0.0</modelVersion> 20 <modelVersion>4.0.0</modelVersion>
21 <parent> 21 <parent>
22 <groupId>org.thingsboard</groupId> 22 <groupId>org.thingsboard</groupId>
23 - <version>2.5.1-SNAPSHOT</version> 23 + <version>2.5.3-SNAPSHOT</version>
24 <artifactId>common</artifactId> 24 <artifactId>common</artifactId>
25 </parent> 25 </parent>
26 <groupId>org.thingsboard.common</groupId> 26 <groupId>org.thingsboard.common</groupId>
@@ -21,7 +21,6 @@ import org.thingsboard.server.common.msg.queue.QueueToRuleEngineMsg; @@ -21,7 +21,6 @@ import org.thingsboard.server.common.msg.queue.QueueToRuleEngineMsg;
21 /** 21 /**
22 * Created by ashvayka on 15.03.18. 22 * Created by ashvayka on 15.03.18.
23 */ 23 */
24 -//TODO: add all "See" references  
25 public enum MsgType { 24 public enum MsgType {
26 25
27 /** 26 /**
@@ -97,6 +96,7 @@ public enum MsgType { @@ -97,6 +96,7 @@ public enum MsgType {
97 96
98 STATS_PERSIST_TICK_MSG, 97 STATS_PERSIST_TICK_MSG,
99 98
  99 + STATS_PERSIST_MSG,
100 100
101 /** 101 /**
102 * Message that is sent by TransportRuleEngineService to Device Actor. Represents messages from the device itself. 102 * Message that is sent by TransportRuleEngineService to Device Actor. Represents messages from the device itself.
@@ -25,6 +25,7 @@ import org.thingsboard.server.common.data.id.EntityIdFactory; @@ -25,6 +25,7 @@ import org.thingsboard.server.common.data.id.EntityIdFactory;
25 import org.thingsboard.server.common.data.id.RuleChainId; 25 import org.thingsboard.server.common.data.id.RuleChainId;
26 import org.thingsboard.server.common.data.id.RuleNodeId; 26 import org.thingsboard.server.common.data.id.RuleNodeId;
27 import org.thingsboard.server.common.msg.gen.MsgProtos; 27 import org.thingsboard.server.common.msg.gen.MsgProtos;
  28 +import org.thingsboard.server.common.msg.queue.ServiceQueue;
28 import org.thingsboard.server.common.msg.queue.TbMsgCallback; 29 import org.thingsboard.server.common.msg.queue.TbMsgCallback;
29 30
30 import java.io.IOException; 31 import java.io.IOException;
@@ -39,6 +40,7 @@ import java.util.UUID; @@ -39,6 +40,7 @@ import java.util.UUID;
39 @Slf4j 40 @Slf4j
40 public final class TbMsg implements Serializable { 41 public final class TbMsg implements Serializable {
41 42
  43 + private final String queueName;
42 private final UUID id; 44 private final UUID id;
43 private final long ts; 45 private final long ts;
44 private final String type; 46 private final String type;
@@ -51,39 +53,44 @@ public final class TbMsg implements Serializable { @@ -51,39 +53,44 @@ public final class TbMsg implements Serializable {
51 //This field is not serialized because we use queues and there is no need to do it 53 //This field is not serialized because we use queues and there is no need to do it
52 transient private final TbMsgCallback callback; 54 transient private final TbMsgCallback callback;
53 55
  56 + public static TbMsg newMsg(String queueName, String type, EntityId originator, TbMsgMetaData metaData, String data, RuleChainId ruleChainId, RuleNodeId ruleNodeId) {
  57 + return new TbMsg(queueName, UUID.randomUUID(), System.currentTimeMillis(), type, originator, metaData.copy(), TbMsgDataType.JSON, data, ruleChainId, ruleNodeId, TbMsgCallback.EMPTY);
  58 + }
  59 +
54 public static TbMsg newMsg(String type, EntityId originator, TbMsgMetaData metaData, String data) { 60 public static TbMsg newMsg(String type, EntityId originator, TbMsgMetaData metaData, String data) {
55 - return new TbMsg(UUID.randomUUID(), System.currentTimeMillis(), type, originator, metaData.copy(), TbMsgDataType.JSON, data, null, null, TbMsgCallback.EMPTY); 61 + return new TbMsg(ServiceQueue.MAIN, UUID.randomUUID(), System.currentTimeMillis(), type, originator, metaData.copy(), TbMsgDataType.JSON, data, null, null, TbMsgCallback.EMPTY);
56 } 62 }
57 63
58 - public static TbMsg newMsg(String type, EntityId originator, TbMsgMetaData metaData, String data, RuleChainId ruleChainId, RuleNodeId ruleNodeId) {  
59 - return new TbMsg(UUID.randomUUID(), System.currentTimeMillis(), type, originator, metaData.copy(), TbMsgDataType.JSON, data, ruleChainId, ruleNodeId, TbMsgCallback.EMPTY); 64 + public static TbMsg newMsg(String queueName, String type, EntityId originator, TbMsgMetaData metaData, String data) {
  65 + return new TbMsg(queueName, UUID.randomUUID(), System.currentTimeMillis(), type, originator, metaData.copy(), TbMsgDataType.JSON, data, null, null, TbMsgCallback.EMPTY);
60 } 66 }
61 67
62 public static TbMsg newMsg(String type, EntityId originator, TbMsgMetaData metaData, TbMsgDataType dataType, String data) { 68 public static TbMsg newMsg(String type, EntityId originator, TbMsgMetaData metaData, TbMsgDataType dataType, String data) {
63 - return new TbMsg(UUID.randomUUID(), System.currentTimeMillis(), type, originator, metaData.copy(), dataType, data, null, null, TbMsgCallback.EMPTY); 69 + return new TbMsg(ServiceQueue.MAIN, UUID.randomUUID(), System.currentTimeMillis(), type, originator, metaData.copy(), dataType, data, null, null, TbMsgCallback.EMPTY);
64 } 70 }
65 71
66 public static TbMsg newMsg(String type, EntityId originator, TbMsgMetaData metaData, TbMsgDataType dataType, String data, RuleChainId ruleChainId, RuleNodeId ruleNodeId) { 72 public static TbMsg newMsg(String type, EntityId originator, TbMsgMetaData metaData, TbMsgDataType dataType, String data, RuleChainId ruleChainId, RuleNodeId ruleNodeId) {
67 - return new TbMsg(UUID.randomUUID(), System.currentTimeMillis(), type, originator, metaData.copy(), dataType, data, ruleChainId, ruleNodeId, TbMsgCallback.EMPTY); 73 + return new TbMsg(ServiceQueue.MAIN, UUID.randomUUID(), System.currentTimeMillis(), type, originator, metaData.copy(), dataType, data, ruleChainId, ruleNodeId, TbMsgCallback.EMPTY);
68 } 74 }
69 75
70 public static TbMsg newMsg(String type, EntityId originator, TbMsgMetaData metaData, String data, TbMsgCallback callback) { 76 public static TbMsg newMsg(String type, EntityId originator, TbMsgMetaData metaData, String data, TbMsgCallback callback) {
71 - return new TbMsg(UUID.randomUUID(), System.currentTimeMillis(), type, originator, metaData.copy(), TbMsgDataType.JSON, data, null, null, callback); 77 + return new TbMsg(ServiceQueue.MAIN, UUID.randomUUID(), System.currentTimeMillis(), type, originator, metaData.copy(), TbMsgDataType.JSON, data, null, null, callback);
72 } 78 }
73 79
74 public static TbMsg transformMsg(TbMsg origMsg, String type, EntityId originator, TbMsgMetaData metaData, String data) { 80 public static TbMsg transformMsg(TbMsg origMsg, String type, EntityId originator, TbMsgMetaData metaData, String data) {
75 - return new TbMsg(origMsg.getId(), origMsg.getTs(), type, originator, metaData.copy(), origMsg.getDataType(), 81 + return new TbMsg(origMsg.getQueueName(), origMsg.getId(), origMsg.getTs(), type, originator, metaData.copy(), origMsg.getDataType(),
76 data, origMsg.getRuleChainId(), origMsg.getRuleNodeId(), origMsg.getCallback()); 82 data, origMsg.getRuleChainId(), origMsg.getRuleNodeId(), origMsg.getCallback());
77 } 83 }
78 84
79 public static TbMsg newMsg(TbMsg tbMsg, RuleChainId ruleChainId, RuleNodeId ruleNodeId) { 85 public static TbMsg newMsg(TbMsg tbMsg, RuleChainId ruleChainId, RuleNodeId ruleNodeId) {
80 - return new TbMsg(UUID.randomUUID(), tbMsg.getTs(), tbMsg.getType(), tbMsg.getOriginator(), tbMsg.getMetaData().copy(), 86 + return new TbMsg(tbMsg.getQueueName(), UUID.randomUUID(), tbMsg.getTs(), tbMsg.getType(), tbMsg.getOriginator(), tbMsg.getMetaData().copy(),
81 tbMsg.getDataType(), tbMsg.getData(), ruleChainId, ruleNodeId, TbMsgCallback.EMPTY); 87 tbMsg.getDataType(), tbMsg.getData(), ruleChainId, ruleNodeId, TbMsgCallback.EMPTY);
82 } 88 }
83 89
84 - private TbMsg(UUID id, long ts, String type, EntityId originator, TbMsgMetaData metaData, TbMsgDataType dataType, String data, 90 + private TbMsg(String queueName, UUID id, long ts, String type, EntityId originator, TbMsgMetaData metaData, TbMsgDataType dataType, String data,
85 RuleChainId ruleChainId, RuleNodeId ruleNodeId, TbMsgCallback callback) { 91 RuleChainId ruleChainId, RuleNodeId ruleNodeId, TbMsgCallback callback) {
86 this.id = id; 92 this.id = id;
  93 + this.queueName = queueName;
87 if (ts > 0) { 94 if (ts > 0) {
88 this.ts = ts; 95 this.ts = ts;
89 } else { 96 } else {
@@ -136,7 +143,7 @@ public final class TbMsg implements Serializable { @@ -136,7 +143,7 @@ public final class TbMsg implements Serializable {
136 return builder.build().toByteArray(); 143 return builder.build().toByteArray();
137 } 144 }
138 145
139 - public static TbMsg fromBytes(byte[] data, TbMsgCallback callback) { 146 + public static TbMsg fromBytes(String queueName, byte[] data, TbMsgCallback callback) {
140 try { 147 try {
141 MsgProtos.TbMsgProto proto = MsgProtos.TbMsgProto.parseFrom(data); 148 MsgProtos.TbMsgProto proto = MsgProtos.TbMsgProto.parseFrom(data);
142 TbMsgMetaData metaData = new TbMsgMetaData(proto.getMetaData().getDataMap()); 149 TbMsgMetaData metaData = new TbMsgMetaData(proto.getMetaData().getDataMap());
@@ -150,18 +157,18 @@ public final class TbMsg implements Serializable { @@ -150,18 +157,18 @@ public final class TbMsg implements Serializable {
150 ruleNodeId = new RuleNodeId(new UUID(proto.getRuleNodeIdMSB(), proto.getRuleNodeIdLSB())); 157 ruleNodeId = new RuleNodeId(new UUID(proto.getRuleNodeIdMSB(), proto.getRuleNodeIdLSB()));
151 } 158 }
152 TbMsgDataType dataType = TbMsgDataType.values()[proto.getDataType()]; 159 TbMsgDataType dataType = TbMsgDataType.values()[proto.getDataType()];
153 - return new TbMsg(UUID.fromString(proto.getId()), proto.getTs(), proto.getType(), entityId, metaData, dataType, proto.getData(), ruleChainId, ruleNodeId, callback); 160 + return new TbMsg(queueName, UUID.fromString(proto.getId()), proto.getTs(), proto.getType(), entityId, metaData, dataType, proto.getData(), ruleChainId, ruleNodeId, callback);
154 } catch (InvalidProtocolBufferException e) { 161 } catch (InvalidProtocolBufferException e) {
155 throw new IllegalStateException("Could not parse protobuf for TbMsg", e); 162 throw new IllegalStateException("Could not parse protobuf for TbMsg", e);
156 } 163 }
157 } 164 }
158 165
159 public TbMsg copyWithRuleChainId(RuleChainId ruleChainId) { 166 public TbMsg copyWithRuleChainId(RuleChainId ruleChainId) {
160 - return new TbMsg(this.id, this.ts, this.type, this.originator, this.metaData, this.dataType, this.data, ruleChainId, null, callback); 167 + return new TbMsg(this.queueName, this.id, this.ts, this.type, this.originator, this.metaData, this.dataType, this.data, ruleChainId, null, callback);
161 } 168 }
162 169
163 public TbMsg copyWithRuleNodeId(RuleChainId ruleChainId, RuleNodeId ruleNodeId) { 170 public TbMsg copyWithRuleNodeId(RuleChainId ruleChainId, RuleNodeId ruleNodeId) {
164 - return new TbMsg(this.id, this.ts, this.type, this.originator, this.metaData, this.dataType, this.data, ruleChainId, ruleNodeId, callback); 171 + return new TbMsg(this.queueName, this.id, this.ts, this.type, this.originator, this.metaData, this.dataType, this.data, ruleChainId, ruleNodeId, callback);
165 } 172 }
166 173
167 public TbMsgCallback getCallback() { 174 public TbMsgCallback getCallback() {
@@ -172,4 +179,8 @@ public final class TbMsg implements Serializable { @@ -172,4 +179,8 @@ public final class TbMsg implements Serializable {
172 return TbMsgCallback.EMPTY; 179 return TbMsgCallback.EMPTY;
173 } 180 }
174 } 181 }
  182 +
  183 + public String getQueueName() {
  184 + return queueName != null ? queueName : ServiceQueue.MAIN;
  185 + }
175 } 186 }
@@ -16,8 +16,9 @@ @@ -16,8 +16,9 @@
16 package org.thingsboard.server.common.msg.aware; 16 package org.thingsboard.server.common.msg.aware;
17 17
18 import org.thingsboard.server.common.data.id.DeviceId; 18 import org.thingsboard.server.common.data.id.DeviceId;
  19 +import org.thingsboard.server.common.msg.TbActorMsg;
19 20
20 -public interface DeviceAwareMsg { 21 +public interface DeviceAwareMsg extends TbActorMsg {
21 22
22 DeviceId getDeviceId(); 23 DeviceId getDeviceId();
23 } 24 }
@@ -16,8 +16,9 @@ @@ -16,8 +16,9 @@
16 package org.thingsboard.server.common.msg.aware; 16 package org.thingsboard.server.common.msg.aware;
17 17
18 import org.thingsboard.server.common.data.id.RuleChainId; 18 import org.thingsboard.server.common.data.id.RuleChainId;
  19 +import org.thingsboard.server.common.msg.TbActorMsg;
19 20
20 -public interface RuleChainAwareMsg { 21 +public interface RuleChainAwareMsg extends TbActorMsg {
21 22
22 RuleChainId getRuleChainId(); 23 RuleChainId getRuleChainId();
23 24
@@ -16,8 +16,9 @@ @@ -16,8 +16,9 @@
16 package org.thingsboard.server.common.msg.aware; 16 package org.thingsboard.server.common.msg.aware;
17 17
18 import org.thingsboard.server.common.data.id.TenantId; 18 import org.thingsboard.server.common.data.id.TenantId;
  19 +import org.thingsboard.server.common.msg.TbActorMsg;
19 20
20 -public interface TenantAwareMsg { 21 +public interface TenantAwareMsg extends TbActorMsg {
21 22
22 TenantId getTenantId(); 23 TenantId getTenantId();
23 24
@@ -34,7 +34,7 @@ public class ServiceQueue { @@ -34,7 +34,7 @@ public class ServiceQueue {
34 34
35 public ServiceQueue(ServiceType type, String queue) { 35 public ServiceQueue(ServiceType type, String queue) {
36 this.type = type; 36 this.type = type;
37 - this.queue = queue; 37 + this.queue = queue != null ? queue : MAIN;
38 } 38 }
39 39
40 public ServiceType getType() { 40 public ServiceType getType() {
@@ -20,7 +20,7 @@ @@ -20,7 +20,7 @@
20 <modelVersion>4.0.0</modelVersion> 20 <modelVersion>4.0.0</modelVersion>
21 <parent> 21 <parent>
22 <groupId>org.thingsboard</groupId> 22 <groupId>org.thingsboard</groupId>
23 - <version>2.5.1-SNAPSHOT</version> 23 + <version>2.5.3-SNAPSHOT</version>
24 <artifactId>thingsboard</artifactId> 24 <artifactId>thingsboard</artifactId>
25 </parent> 25 </parent>
26 <artifactId>common</artifactId> 26 <artifactId>common</artifactId>
@@ -37,6 +37,7 @@ @@ -37,6 +37,7 @@
37 <module>data</module> 37 <module>data</module>
38 <module>util</module> 38 <module>util</module>
39 <module>message</module> 39 <module>message</module>
  40 + <module>actor</module>
40 <module>queue</module> 41 <module>queue</module>
41 <module>transport</module> 42 <module>transport</module>
42 <module>dao-api</module> 43 <module>dao-api</module>
@@ -20,7 +20,7 @@ @@ -20,7 +20,7 @@
20 <modelVersion>4.0.0</modelVersion> 20 <modelVersion>4.0.0</modelVersion>
21 <parent> 21 <parent>
22 <groupId>org.thingsboard</groupId> 22 <groupId>org.thingsboard</groupId>
23 - <version>2.5.1-SNAPSHOT</version> 23 + <version>2.5.3-SNAPSHOT</version>
24 <artifactId>common</artifactId> 24 <artifactId>common</artifactId>
25 </parent> 25 </parent>
26 <groupId>org.thingsboard.common</groupId> 26 <groupId>org.thingsboard.common</groupId>
@@ -91,8 +91,6 @@ public class DefaultTbQueueRequestTemplate<Request extends TbQueueMsg, Response @@ -91,8 +91,6 @@ public class DefaultTbQueueRequestTemplate<Request extends TbQueueMsg, Response
91 List<Response> responses = responseTemplate.poll(pollInterval); 91 List<Response> responses = responseTemplate.poll(pollInterval);
92 if (responses.size() > 0) { 92 if (responses.size() > 0) {
93 log.trace("Polling responses completed, consumer records count [{}]", responses.size()); 93 log.trace("Polling responses completed, consumer records count [{}]", responses.size());
94 - } else {  
95 - continue;  
96 } 94 }
97 responses.forEach(response -> { 95 responses.forEach(response -> {
98 byte[] requestIdHeader = response.getHeaders().get(REQUEST_ID_HEADER); 96 byte[] requestIdHeader = response.getHeaders().get(REQUEST_ID_HEADER);
@@ -20,7 +20,7 @@ @@ -20,7 +20,7 @@
20 <modelVersion>4.0.0</modelVersion> 20 <modelVersion>4.0.0</modelVersion>
21 <parent> 21 <parent>
22 <groupId>org.thingsboard.common</groupId> 22 <groupId>org.thingsboard.common</groupId>
23 - <version>2.5.1-SNAPSHOT</version> 23 + <version>2.5.3-SNAPSHOT</version>
24 <artifactId>transport</artifactId> 24 <artifactId>transport</artifactId>
25 </parent> 25 </parent>
26 <groupId>org.thingsboard.common.transport</groupId> 26 <groupId>org.thingsboard.common.transport</groupId>
@@ -20,7 +20,7 @@ @@ -20,7 +20,7 @@
20 <modelVersion>4.0.0</modelVersion> 20 <modelVersion>4.0.0</modelVersion>
21 <parent> 21 <parent>
22 <groupId>org.thingsboard.common</groupId> 22 <groupId>org.thingsboard.common</groupId>
23 - <version>2.5.1-SNAPSHOT</version> 23 + <version>2.5.3-SNAPSHOT</version>
24 <artifactId>transport</artifactId> 24 <artifactId>transport</artifactId>
25 </parent> 25 </parent>
26 <groupId>org.thingsboard.common.transport</groupId> 26 <groupId>org.thingsboard.common.transport</groupId>
@@ -20,7 +20,7 @@ @@ -20,7 +20,7 @@
20 <modelVersion>4.0.0</modelVersion> 20 <modelVersion>4.0.0</modelVersion>
21 <parent> 21 <parent>
22 <groupId>org.thingsboard.common</groupId> 22 <groupId>org.thingsboard.common</groupId>
23 - <version>2.5.1-SNAPSHOT</version> 23 + <version>2.5.3-SNAPSHOT</version>
24 <artifactId>transport</artifactId> 24 <artifactId>transport</artifactId>
25 </parent> 25 </parent>
26 <groupId>org.thingsboard.common.transport</groupId> 26 <groupId>org.thingsboard.common.transport</groupId>
@@ -521,11 +521,22 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement @@ -521,11 +521,22 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement
521 .setDeviceName(msg.getDeviceInfo().getDeviceName()) 521 .setDeviceName(msg.getDeviceInfo().getDeviceName())
522 .setDeviceType(msg.getDeviceInfo().getDeviceType()) 522 .setDeviceType(msg.getDeviceInfo().getDeviceType())
523 .build(); 523 .build();
524 - transportService.process(sessionInfo, DefaultTransportService.getSessionEventMsg(SessionEvent.OPEN), null);  
525 - transportService.registerAsyncSession(sessionInfo, this);  
526 - checkGatewaySession();  
527 - ctx.writeAndFlush(createMqttConnAckMsg(CONNECTION_ACCEPTED));  
528 - log.info("[{}] Client connected!", sessionId); 524 + transportService.process(sessionInfo, DefaultTransportService.getSessionEventMsg(SessionEvent.OPEN), new TransportServiceCallback<Void>() {
  525 + @Override
  526 + public void onSuccess(Void msg) {
  527 + transportService.registerAsyncSession(sessionInfo, MqttTransportHandler.this);
  528 + checkGatewaySession();
  529 + ctx.writeAndFlush(createMqttConnAckMsg(CONNECTION_ACCEPTED));
  530 + log.info("[{}] Client connected!", sessionId);
  531 + }
  532 +
  533 + @Override
  534 + public void onError(Throwable e) {
  535 + log.warn("[{}] Failed to submit session event", sessionId, e);
  536 + ctx.writeAndFlush(createMqttConnAckMsg(MqttConnectReturnCode.CONNECTION_REFUSED_SERVER_UNAVAILABLE));
  537 + ctx.close();
  538 + }
  539 + });
529 } 540 }
530 } 541 }
531 542
@@ -20,7 +20,7 @@ @@ -20,7 +20,7 @@
20 <modelVersion>4.0.0</modelVersion> 20 <modelVersion>4.0.0</modelVersion>
21 <parent> 21 <parent>
22 <groupId>org.thingsboard</groupId> 22 <groupId>org.thingsboard</groupId>
23 - <version>2.5.1-SNAPSHOT</version> 23 + <version>2.5.3-SNAPSHOT</version>
24 <artifactId>common</artifactId> 24 <artifactId>common</artifactId>
25 </parent> 25 </parent>
26 <groupId>org.thingsboard.common</groupId> 26 <groupId>org.thingsboard.common</groupId>
@@ -20,7 +20,7 @@ @@ -20,7 +20,7 @@
20 <modelVersion>4.0.0</modelVersion> 20 <modelVersion>4.0.0</modelVersion>
21 <parent> 21 <parent>
22 <groupId>org.thingsboard.common</groupId> 22 <groupId>org.thingsboard.common</groupId>
23 - <version>2.5.1-SNAPSHOT</version> 23 + <version>2.5.3-SNAPSHOT</version>
24 <artifactId>transport</artifactId> 24 <artifactId>transport</artifactId>
25 </parent> 25 </parent>
26 <groupId>org.thingsboard.common.transport</groupId> 26 <groupId>org.thingsboard.common.transport</groupId>
@@ -20,7 +20,7 @@ @@ -20,7 +20,7 @@
20 <modelVersion>4.0.0</modelVersion> 20 <modelVersion>4.0.0</modelVersion>
21 <parent> 21 <parent>
22 <groupId>org.thingsboard</groupId> 22 <groupId>org.thingsboard</groupId>
23 - <version>2.5.1-SNAPSHOT</version> 23 + <version>2.5.3-SNAPSHOT</version>
24 <artifactId>common</artifactId> 24 <artifactId>common</artifactId>
25 </parent> 25 </parent>
26 <groupId>org.thingsboard.common</groupId> 26 <groupId>org.thingsboard.common</groupId>
@@ -20,7 +20,7 @@ @@ -20,7 +20,7 @@
20 <modelVersion>4.0.0</modelVersion> 20 <modelVersion>4.0.0</modelVersion>
21 <parent> 21 <parent>
22 <groupId>org.thingsboard</groupId> 22 <groupId>org.thingsboard</groupId>
23 - <version>2.5.1-SNAPSHOT</version> 23 + <version>2.5.3-SNAPSHOT</version>
24 <artifactId>thingsboard</artifactId> 24 <artifactId>thingsboard</artifactId>
25 </parent> 25 </parent>
26 <artifactId>dao</artifactId> 26 <artifactId>dao</artifactId>
@@ -91,26 +91,26 @@ @@ -91,26 +91,26 @@
91 <artifactId>mockito-all</artifactId> 91 <artifactId>mockito-all</artifactId>
92 <scope>test</scope> 92 <scope>test</scope>
93 </dependency> 93 </dependency>
94 - <dependency>  
95 - <groupId>org.apache.commons</groupId>  
96 - <artifactId>commons-lang3</artifactId>  
97 - </dependency>  
98 - <dependency>  
99 - <groupId>commons-validator</groupId>  
100 - <artifactId>commons-validator</artifactId>  
101 - </dependency>  
102 - <dependency>  
103 - <groupId>com.fasterxml.jackson.core</groupId>  
104 - <artifactId>jackson-databind</artifactId>  
105 - </dependency> 94 + <dependency>
  95 + <groupId>org.apache.commons</groupId>
  96 + <artifactId>commons-lang3</artifactId>
  97 + </dependency>
  98 + <dependency>
  99 + <groupId>commons-collections</groupId>
  100 + <artifactId>commons-collections</artifactId>
  101 + </dependency>
  102 + <dependency>
  103 + <groupId>com.fasterxml.jackson.core</groupId>
  104 + <artifactId>jackson-databind</artifactId>
  105 + </dependency>
106 <dependency> 106 <dependency>
107 <groupId>org.springframework</groupId> 107 <groupId>org.springframework</groupId>
108 <artifactId>spring-context</artifactId> 108 <artifactId>spring-context</artifactId>
109 </dependency> 109 </dependency>
110 - <dependency>  
111 - <groupId>org.springframework</groupId>  
112 - <artifactId>spring-tx</artifactId>  
113 - </dependency> 110 + <dependency>
  111 + <groupId>org.springframework</groupId>
  112 + <artifactId>spring-tx</artifactId>
  113 + </dependency>
114 <dependency> 114 <dependency>
115 <groupId>org.springframework</groupId> 115 <groupId>org.springframework</groupId>
116 <artifactId>spring-web</artifactId> 116 <artifactId>spring-web</artifactId>
@@ -120,24 +120,24 @@ @@ -120,24 +120,24 @@
120 <groupId>org.springframework.security</groupId> 120 <groupId>org.springframework.security</groupId>
121 <artifactId>spring-security-oauth2-client</artifactId> 121 <artifactId>spring-security-oauth2-client</artifactId>
122 </dependency> 122 </dependency>
123 - <dependency>  
124 - <groupId>com.datastax.cassandra</groupId>  
125 - <artifactId>cassandra-driver-core</artifactId>  
126 - </dependency>  
127 - <dependency>  
128 - <groupId>com.datastax.cassandra</groupId>  
129 - <artifactId>cassandra-driver-mapping</artifactId>  
130 - </dependency>  
131 - <dependency>  
132 - <groupId>com.datastax.cassandra</groupId>  
133 - <artifactId>cassandra-driver-extras</artifactId>  
134 - </dependency> 123 + <dependency>
  124 + <groupId>com.datastax.cassandra</groupId>
  125 + <artifactId>cassandra-driver-core</artifactId>
  126 + </dependency>
  127 + <dependency>
  128 + <groupId>com.datastax.cassandra</groupId>
  129 + <artifactId>cassandra-driver-mapping</artifactId>
  130 + </dependency>
  131 + <dependency>
  132 + <groupId>com.datastax.cassandra</groupId>
  133 + <artifactId>cassandra-driver-extras</artifactId>
  134 + </dependency>
135 <dependency> 135 <dependency>
136 <groupId>io.takari.junit</groupId> 136 <groupId>io.takari.junit</groupId>
137 <artifactId>takari-cpsuite</artifactId> 137 <artifactId>takari-cpsuite</artifactId>
138 <scope>test</scope> 138 <scope>test</scope>
139 - </dependency>  
140 - <dependency> 139 + </dependency>
  140 + <dependency>
141 <groupId>com.google.guava</groupId> 141 <groupId>com.google.guava</groupId>
142 <artifactId>guava</artifactId> 142 <artifactId>guava</artifactId>
143 </dependency> 143 </dependency>
@@ -215,18 +215,18 @@ @@ -215,18 +215,18 @@
215 </includes> 215 </includes>
216 </configuration> 216 </configuration>
217 </plugin> 217 </plugin>
218 - <plugin>  
219 - <groupId>org.apache.maven.plugins</groupId>  
220 - <artifactId>maven-jar-plugin</artifactId> 218 + <plugin>
  219 + <groupId>org.apache.maven.plugins</groupId>
  220 + <artifactId>maven-jar-plugin</artifactId>
221 <version>${jar-plugin.version}</version> 221 <version>${jar-plugin.version}</version>
222 - <executions>  
223 - <execution>  
224 - <goals>  
225 - <goal>test-jar</goal>  
226 - </goals>  
227 - </execution>  
228 - </executions>  
229 - </plugin> 222 + <executions>
  223 + <execution>
  224 + <goals>
  225 + <goal>test-jar</goal>
  226 + </goals>
  227 + </execution>
  228 + </executions>
  229 + </plugin>
230 </plugins> 230 </plugins>
231 </build> 231 </build>
232 </project> 232 </project>
@@ -17,7 +17,6 @@ package org.thingsboard.server.dao.service; @@ -17,7 +17,6 @@ package org.thingsboard.server.dao.service;
17 17
18 import com.fasterxml.jackson.databind.JsonNode; 18 import com.fasterxml.jackson.databind.JsonNode;
19 import lombok.extern.slf4j.Slf4j; 19 import lombok.extern.slf4j.Slf4j;
20 -import org.apache.commons.validator.routines.EmailValidator;  
21 import org.thingsboard.server.common.data.BaseData; 20 import org.thingsboard.server.common.data.BaseData;
22 import org.thingsboard.server.common.data.id.TenantId; 21 import org.thingsboard.server.common.data.id.TenantId;
23 import org.thingsboard.server.dao.exception.DataValidationException; 22 import org.thingsboard.server.dao.exception.DataValidationException;
@@ -26,11 +25,13 @@ import java.util.HashSet; @@ -26,11 +25,13 @@ import java.util.HashSet;
26 import java.util.Iterator; 25 import java.util.Iterator;
27 import java.util.Set; 26 import java.util.Set;
28 import java.util.function.Function; 27 import java.util.function.Function;
  28 +import java.util.regex.Matcher;
  29 +import java.util.regex.Pattern;
29 30
30 @Slf4j 31 @Slf4j
31 public abstract class DataValidator<D extends BaseData<?>> { 32 public abstract class DataValidator<D extends BaseData<?>> {
32 -  
33 - private static EmailValidator emailValidator = EmailValidator.getInstance(); 33 + private static final Pattern EMAIL_PATTERN =
  34 + Pattern.compile("^[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,6}$", Pattern.CASE_INSENSITIVE);
34 35
35 public void validate(D data, Function<D, TenantId> tenantIdFunction) { 36 public void validate(D data, Function<D, TenantId> tenantIdFunction) {
36 try { 37 try {
@@ -64,11 +65,20 @@ public abstract class DataValidator<D extends BaseData<?>> { @@ -64,11 +65,20 @@ public abstract class DataValidator<D extends BaseData<?>> {
64 } 65 }
65 66
66 protected static void validateEmail(String email) { 67 protected static void validateEmail(String email) {
67 - if (!emailValidator.isValid(email)) { 68 + if (!doValidateEmail(email)) {
68 throw new DataValidationException("Invalid email address format '" + email + "'!"); 69 throw new DataValidationException("Invalid email address format '" + email + "'!");
69 } 70 }
70 } 71 }
71 72
  73 + private static boolean doValidateEmail(String email) {
  74 + if (email == null) {
  75 + return false;
  76 + }
  77 +
  78 + Matcher emailMatcher = EMAIL_PATTERN.matcher(email);
  79 + return emailMatcher.matches();
  80 + }
  81 +
72 protected static void validateJsonStructure(JsonNode expectedNode, JsonNode actualNode) { 82 protected static void validateJsonStructure(JsonNode expectedNode, JsonNode actualNode) {
73 Set<String> expectedFields = new HashSet<>(); 83 Set<String> expectedFields = new HashSet<>();
74 Iterator<String> fieldsIterator = expectedNode.fieldNames(); 84 Iterator<String> fieldsIterator = expectedNode.fieldNames();
@@ -4,15 +4,15 @@ This folder containing scripts and Kubernetes resources configurations to run Th @@ -4,15 +4,15 @@ This folder containing scripts and Kubernetes resources configurations to run Th
4 4
5 ## Prerequisites 5 ## Prerequisites
6 6
7 -ThingsBoard Microservices are running on Kubernetes cluster. 7 +ThingsBoard Microservices run on the Kubernetes cluster.
8 You need to have a Kubernetes cluster, and the kubectl command-line tool must be configured to communicate with your cluster. 8 You need to have a Kubernetes cluster, and the kubectl command-line tool must be configured to communicate with your cluster.
9 -If you do not already have a cluster, you can create one by using [Minikube](https://kubernetes.io/docs/setup/minikube), 9 +If you do not have a cluster already, you can create one by using [Minikube](https://kubernetes.io/docs/setup/minikube),
10 or you can choose any other available [Kubernetes cluster deployment solutions](https://kubernetes.io/docs/setup/pick-right-solution/). 10 or you can choose any other available [Kubernetes cluster deployment solutions](https://kubernetes.io/docs/setup/pick-right-solution/).
11 11
12 ### Enable ingress addon 12 ### Enable ingress addon
13 13
14 -By default ingress addon is disable in the Minikube, and available only in cluster providers.  
15 -To enable ingress, please execute next command: 14 +By default ingress addon is disabled in the Minikube, and available only in cluster providers.
  15 +To enable ingress, please execute the following command:
16 16
17 ` 17 `
18 $ minikube addons enable ingress 18 $ minikube addons enable ingress
@@ -21,21 +21,21 @@ $ minikube addons enable ingress @@ -21,21 +21,21 @@ $ minikube addons enable ingress
21 ## Installation 21 ## Installation
22 22
23 Before performing initial installation you can configure the type of database to be used with ThingsBoard and the type of deployment. 23 Before performing initial installation you can configure the type of database to be used with ThingsBoard and the type of deployment.
24 -In order to set database type change the value of `DATABASE` variable in `.env` file to one of the following: 24 +To set database type change the value of `DATABASE` variable in `.env` file to one of the following:
25 25
26 - `postgres` - use PostgreSQL database; 26 - `postgres` - use PostgreSQL database;
27 - `cassandra` - use Cassandra database; 27 - `cassandra` - use Cassandra database;
28 28
29 **NOTE**: According to the database type corresponding kubernetes resources will be deployed (see `postgres.yml`, `cassandra.yml` for details). 29 **NOTE**: According to the database type corresponding kubernetes resources will be deployed (see `postgres.yml`, `cassandra.yml` for details).
30 30
31 -In order to set deployment type change the value of `DEPLOYMENT_TYPE` variable in `.env` file to one of the following: 31 +To set deployment type change the value of `DEPLOYMENT_TYPE` variable in `.env` file to one of the following:
32 32
33 -- `basic` - start up with single instance of Zookeeper, Kafka and Redis;  
34 -- `high-availability` - start up with Zookeeper, Kafka and Redis in cluster modes; 33 +- `basic` - startup with a single instance of Zookeeper, Kafka and Redis;
  34 +- `high-availability` - startup with Zookeeper, Kafka, and Redis in cluster modes;
35 35
36 -**NOTE**: According to the deployment type corresponding kubernetes resources will be deployed (see content of the directories `./basic` and `./high-availability` for details). 36 +**NOTE**: According to the deployment type corresponding kubernetes resources will be deployed (see the content of the directories `./basic` and `./high-availability` for details).
37 37
38 -Execute the following command to run installation: 38 +Execute the following command to run the installation:
39 39
40 ` 40 `
41 $ ./k8s-install-tb.sh --loadDemo 41 $ ./k8s-install-tb.sh --loadDemo
@@ -47,7 +47,7 @@ Where: @@ -47,7 +47,7 @@ Where:
47 47
48 ## Running 48 ## Running
49 49
50 -Execute the following command to deploy thirdparty resources: 50 +Execute the following command to deploy third-party resources:
51 51
52 ` 52 `
53 $ ./k8s-deploy-thirdparty.sh 53 $ ./k8s-deploy-thirdparty.sh
@@ -61,8 +61,8 @@ Execute the following command to deploy resources: @@ -61,8 +61,8 @@ Execute the following command to deploy resources:
61 $ ./k8s-deploy-resources.sh 61 $ ./k8s-deploy-resources.sh
62 ` 62 `
63 63
64 -After a while when all resources will be successfully started you can open `http://{your-cluster-ip}` in you browser (for ex. `http://192.168.99.101`).  
65 -You should see ThingsBoard login page. 64 +After a while when all resources will be successfully started you can open `http://{your-cluster-ip}` in your browser (for ex. `http://192.168.99.101`).
  65 +You should see the ThingsBoard login page.
66 66
67 Use the following default credentials: 67 Use the following default credentials:
68 68
@@ -73,16 +73,16 @@ If you installed DataBase with demo data (using `--loadDemo` flag) you can also @@ -73,16 +73,16 @@ If you installed DataBase with demo data (using `--loadDemo` flag) you can also
73 - **Tenant Administrator**: tenant@thingsboard.org / tenant 73 - **Tenant Administrator**: tenant@thingsboard.org / tenant
74 - **Customer User**: customer@thingsboard.org / customer 74 - **Customer User**: customer@thingsboard.org / customer
75 75
76 -In case of any issues you can examine service logs for errors. 76 +In case of any issues, you can examine service logs for errors.
77 For example to see ThingsBoard node logs execute the following commands: 77 For example to see ThingsBoard node logs execute the following commands:
78 78
79 -1) Get list of the running tb-node pods: 79 +1) Get the list of the running tb-node pods:
80 80
81 ` 81 `
82 $ kubectl get pods -l app=tb-node 82 $ kubectl get pods -l app=tb-node
83 ` 83 `
84 84
85 -2) Fetch logs of tb-node pod: 85 +2) Fetch logs of the tb-node pod:
86 86
87 ` 87 `
88 $ kubectl logs -f [tb-node-pod-name] 88 $ kubectl logs -f [tb-node-pod-name]
@@ -103,7 +103,7 @@ Execute the following command to delete all ThingsBoard microservices: @@ -103,7 +103,7 @@ Execute the following command to delete all ThingsBoard microservices:
103 $ ./k8s-delete-resources.sh 103 $ ./k8s-delete-resources.sh
104 ` 104 `
105 105
106 -Execute the following command to delete all thirdparty microservices: 106 +Execute the following command to delete all third-party microservices:
107 107
108 ` 108 `
109 $ ./k8s-delete-thirdparty.sh 109 $ ./k8s-delete-thirdparty.sh