Commit 21ee2aec11ae5bf0d0660001987cfeb4b8ba4cea
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 | 20 | <modelVersion>4.0.0</modelVersion> |
21 | 21 | <parent> |
22 | 22 | <groupId>org.thingsboard</groupId> |
23 | - <version>2.5.1-SNAPSHOT</version> | |
23 | + <version>2.5.3-SNAPSHOT</version> | |
24 | 24 | <artifactId>thingsboard</artifactId> |
25 | 25 | </parent> |
26 | 26 | <artifactId>application</artifactId> |
... | ... | @@ -59,6 +59,10 @@ |
59 | 59 | </dependency> |
60 | 60 | <dependency> |
61 | 61 | <groupId>org.thingsboard.common</groupId> |
62 | + <artifactId>actor</artifactId> | |
63 | + </dependency> | |
64 | + <dependency> | |
65 | + <groupId>org.thingsboard.common</groupId> | |
62 | 66 | <artifactId>util</artifactId> |
63 | 67 | </dependency> |
64 | 68 | <dependency> |
... | ... | @@ -178,14 +182,6 @@ |
178 | 182 | <artifactId>spring-context-support</artifactId> |
179 | 183 | </dependency> |
180 | 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 | 185 | <groupId>org.slf4j</groupId> |
190 | 186 | <artifactId>slf4j-api</artifactId> |
191 | 187 | </dependency> |
... | ... | @@ -375,7 +371,7 @@ |
375 | 371 | <repository> |
376 | 372 | <id>jenkins</id> |
377 | 373 | <name>Jenkins Repository</name> |
378 | - <url>http://repo.jenkins-ci.org/releases</url> | |
374 | + <url>https://repo.jenkins-ci.org/releases</url> | |
379 | 375 | <snapshots> |
380 | 376 | <enabled>false</enabled> |
381 | 377 | </snapshots> | ... | ... |
... | ... | @@ -15,9 +15,6 @@ |
15 | 15 | */ |
16 | 16 | package org.thingsboard.server.actors; |
17 | 17 | |
18 | -import akka.actor.ActorRef; | |
19 | -import akka.actor.ActorSystem; | |
20 | -import akka.actor.Scheduler; | |
21 | 18 | import com.fasterxml.jackson.databind.JsonNode; |
22 | 19 | import com.fasterxml.jackson.databind.ObjectMapper; |
23 | 20 | import com.fasterxml.jackson.databind.node.ObjectNode; |
... | ... | @@ -25,8 +22,6 @@ import com.google.common.util.concurrent.FutureCallback; |
25 | 22 | import com.google.common.util.concurrent.Futures; |
26 | 23 | import com.google.common.util.concurrent.ListenableFuture; |
27 | 24 | import com.google.common.util.concurrent.MoreExecutors; |
28 | -import com.typesafe.config.Config; | |
29 | -import com.typesafe.config.ConfigFactory; | |
30 | 25 | import lombok.Getter; |
31 | 26 | import lombok.Setter; |
32 | 27 | import lombok.extern.slf4j.Slf4j; |
... | ... | @@ -93,12 +88,13 @@ import java.io.StringWriter; |
93 | 88 | import java.util.Optional; |
94 | 89 | import java.util.concurrent.ConcurrentHashMap; |
95 | 90 | import java.util.concurrent.ConcurrentMap; |
91 | +import java.util.concurrent.ScheduledExecutorService; | |
92 | +import java.util.concurrent.TimeUnit; | |
96 | 93 | import java.util.concurrent.atomic.AtomicInteger; |
97 | 94 | |
98 | 95 | @Slf4j |
99 | 96 | @Component |
100 | 97 | public class ActorSystemContext { |
101 | - private static final String AKKA_CONF_FILE_NAME = "actor-system.conf"; | |
102 | 98 | |
103 | 99 | protected final ObjectMapper mapper = new ObjectMapper(); |
104 | 100 | |
... | ... | @@ -272,14 +268,6 @@ public class ActorSystemContext { |
272 | 268 | @Getter |
273 | 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 | 271 | @Value("${actors.rule.chain.error_persist_frequency}") |
284 | 272 | @Getter |
285 | 273 | private long ruleChainErrorPersistFrequency; |
... | ... | @@ -339,17 +327,14 @@ public class ActorSystemContext { |
339 | 327 | |
340 | 328 | @Getter |
341 | 329 | @Setter |
342 | - private ActorSystem actorSystem; | |
330 | + private TbActorSystem actorSystem; | |
343 | 331 | |
344 | 332 | @Setter |
345 | - private ActorRef appActor; | |
333 | + private TbActorRef appActor; | |
346 | 334 | |
347 | 335 | @Getter |
348 | 336 | @Setter |
349 | - private ActorRef statsActor; | |
350 | - | |
351 | - @Getter | |
352 | - private final Config config; | |
337 | + private TbActorRef statsActor; | |
353 | 338 | |
354 | 339 | @Autowired(required = false) |
355 | 340 | @Getter |
... | ... | @@ -363,14 +348,8 @@ public class ActorSystemContext { |
363 | 348 | @Getter |
364 | 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 | 355 | public void persistError(TenantId tenantId, EntityId entityId, String method, Exception e) { |
... | ... | @@ -543,7 +522,21 @@ public class ActorSystemContext { |
543 | 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 | } | ... | ... |
application/src/main/java/org/thingsboard/server/actors/TbEntityTypeActorIdPredicate.java
0 → 100644
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 | 15 | */ |
16 | 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 | 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 | 24 | import org.thingsboard.server.actors.service.ContextAwareActor; |
28 | 25 | import org.thingsboard.server.actors.service.ContextBasedCreator; |
29 | 26 | import org.thingsboard.server.actors.service.DefaultActorService; |
30 | 27 | import org.thingsboard.server.actors.tenant.TenantActor; |
31 | 28 | import org.thingsboard.server.common.data.EntityType; |
32 | 29 | import org.thingsboard.server.common.data.Tenant; |
30 | +import org.thingsboard.server.common.data.id.EntityId; | |
33 | 31 | import org.thingsboard.server.common.data.id.TenantId; |
34 | 32 | import org.thingsboard.server.common.data.page.PageDataIterable; |
35 | 33 | import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; |
... | ... | @@ -43,38 +41,27 @@ import org.thingsboard.server.common.msg.queue.ServiceType; |
43 | 41 | import org.thingsboard.server.dao.model.ModelConstants; |
44 | 42 | import org.thingsboard.server.dao.tenant.TenantService; |
45 | 43 | import org.thingsboard.server.service.transport.msg.TransportToDeviceActorMsgWrapper; |
46 | -import scala.concurrent.duration.Duration; | |
47 | 44 | |
48 | 45 | import java.util.HashSet; |
49 | 46 | import java.util.Optional; |
50 | 47 | import java.util.Set; |
51 | 48 | |
49 | +@Slf4j | |
52 | 50 | public class AppActor extends ContextAwareActor { |
53 | 51 | |
54 | 52 | private static final TenantId SYSTEM_TENANT = new TenantId(ModelConstants.NULL_UUID); |
55 | 53 | private final TenantService tenantService; |
56 | - private final BiMap<TenantId, ActorRef> tenantActors; | |
57 | 54 | private final Set<TenantId> deletedTenants; |
58 | 55 | private boolean ruleChainsInitialized; |
59 | 56 | |
60 | 57 | private AppActor(ActorSystemContext systemContext) { |
61 | 58 | super(systemContext); |
62 | 59 | this.tenantService = systemContext.getTenantService(); |
63 | - this.tenantActors = HashBiMap.create(); | |
64 | 60 | this.deletedTenants = new HashSet<>(); |
65 | 61 | } |
66 | 62 | |
67 | 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 | 65 | if (!ruleChainsInitialized) { |
79 | 66 | initTenantActors(); |
80 | 67 | ruleChainsInitialized = true; |
... | ... | @@ -86,7 +73,7 @@ public class AppActor extends ContextAwareActor { |
86 | 73 | case APP_INIT_MSG: |
87 | 74 | break; |
88 | 75 | case PARTITION_CHANGE_MSG: |
89 | - broadcast(msg); | |
76 | + ctx.broadcastToChildren(msg); | |
90 | 77 | break; |
91 | 78 | case COMPONENT_LIFE_CYCLE_MSG: |
92 | 79 | onComponentLifecycleMsg((ComponentLifecycleMsg) msg); |
... | ... | @@ -95,12 +82,14 @@ public class AppActor extends ContextAwareActor { |
95 | 82 | onQueueToRuleEngineMsg((QueueToRuleEngineMsg) msg); |
96 | 83 | break; |
97 | 84 | case TRANSPORT_TO_DEVICE_ACTOR_MSG: |
85 | + onToDeviceActorMsg((TenantAwareMsg) msg, false); | |
86 | + break; | |
98 | 87 | case DEVICE_ATTRIBUTES_UPDATE_TO_DEVICE_ACTOR_MSG: |
99 | 88 | case DEVICE_CREDENTIALS_UPDATE_TO_DEVICE_ACTOR_MSG: |
100 | 89 | case DEVICE_NAME_OR_TYPE_UPDATE_TO_DEVICE_ACTOR_MSG: |
101 | 90 | case DEVICE_RPC_REQUEST_TO_DEVICE_ACTOR_MSG: |
102 | 91 | case SERVER_RPC_RESPONSE_TO_DEVICE_ACTOR_MSG: |
103 | - onToDeviceActorMsg((TenantAwareMsg) msg); | |
92 | + onToDeviceActorMsg((TenantAwareMsg) msg, true); | |
104 | 93 | break; |
105 | 94 | default: |
106 | 95 | return false; |
... | ... | @@ -145,19 +134,15 @@ public class AppActor extends ContextAwareActor { |
145 | 134 | msg.getTbMsg().getCallback().onFailure(new RuleEngineException("Message has system tenant id!")); |
146 | 135 | } else { |
147 | 136 | if (!deletedTenants.contains(msg.getTenantId())) { |
148 | - getOrCreateTenantActor(msg.getTenantId()).tell(msg, self()); | |
137 | + getOrCreateTenantActor(msg.getTenantId()).tell(msg); | |
149 | 138 | } else { |
150 | 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 | 144 | private void onComponentLifecycleMsg(ComponentLifecycleMsg msg) { |
160 | - ActorRef target = null; | |
145 | + TbActorRef target = null; | |
161 | 146 | if (SYSTEM_TENANT.equals(msg.getTenantId())) { |
162 | 147 | log.warn("Message has system tenant id: {}", msg); |
163 | 148 | } else { |
... | ... | @@ -166,25 +151,26 @@ public class AppActor extends ContextAwareActor { |
166 | 151 | log.info("[{}] Handling tenant deleted notification: {}", msg.getTenantId(), msg); |
167 | 152 | TenantId tenantId = new TenantId(msg.getEntityId().getId()); |
168 | 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 | 155 | } else { |
175 | 156 | target = getOrCreateTenantActor(msg.getTenantId()); |
176 | 157 | } |
177 | 158 | } |
178 | 159 | if (target != null) { |
179 | - target.tell(msg, ActorRef.noSender()); | |
160 | + target.tellWithHighPriority(msg); | |
180 | 161 | } else { |
181 | 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 | 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 | 174 | } else { |
189 | 175 | if (msg instanceof TransportToDeviceActorMsgWrapper) { |
190 | 176 | ((TransportToDeviceActorMsgWrapper) msg).getCallback().onSuccess(); |
... | ... | @@ -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 | 189 | public ActorCreator(ActorSystemContext context) { |
223 | 190 | super(context); |
224 | 191 | } |
225 | 192 | |
226 | 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 | 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 | 15 | */ |
16 | 16 | package org.thingsboard.server.actors.device; |
17 | 17 | |
18 | +import lombok.extern.slf4j.Slf4j; | |
18 | 19 | import org.thingsboard.rule.engine.api.msg.DeviceAttributesEventNotificationMsg; |
19 | 20 | import org.thingsboard.rule.engine.api.msg.DeviceNameOrTypeUpdateMsg; |
20 | 21 | import org.thingsboard.server.actors.ActorSystemContext; |
22 | +import org.thingsboard.server.actors.TbActorCtx; | |
23 | +import org.thingsboard.server.actors.TbActorException; | |
21 | 24 | import org.thingsboard.server.actors.service.ContextAwareActor; |
22 | 25 | import org.thingsboard.server.common.data.id.DeviceId; |
23 | 26 | import org.thingsboard.server.common.data.id.TenantId; |
... | ... | @@ -26,6 +29,7 @@ import org.thingsboard.server.common.msg.timeout.DeviceActorServerSideRpcTimeout |
26 | 29 | import org.thingsboard.server.service.rpc.ToDeviceRpcRequestActorMsg; |
27 | 30 | import org.thingsboard.server.service.transport.msg.TransportToDeviceActorMsgWrapper; |
28 | 31 | |
32 | +@Slf4j | |
29 | 33 | public class DeviceActor extends ContextAwareActor { |
30 | 34 | |
31 | 35 | private final DeviceActorMessageProcessor processor; |
... | ... | @@ -36,29 +40,26 @@ public class DeviceActor extends ContextAwareActor { |
36 | 40 | } |
37 | 41 | |
38 | 42 | @Override |
39 | - public void preStart() { | |
43 | + public void init(TbActorCtx ctx) throws TbActorException { | |
44 | + super.init(ctx); | |
40 | 45 | log.debug("[{}][{}] Starting device actor.", processor.tenantId, processor.deviceId); |
41 | 46 | try { |
42 | - processor.initSessionTimeout(context()); | |
47 | + processor.initSessionTimeout(ctx); | |
43 | 48 | log.debug("[{}][{}] Device actor started.", processor.tenantId, processor.deviceId); |
44 | 49 | } catch (Exception e) { |
45 | 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 | 55 | @Override |
50 | - public void postStop() { | |
51 | - | |
52 | - } | |
53 | - | |
54 | - @Override | |
55 | - protected boolean process(TbActorMsg msg) { | |
56 | + protected boolean doProcess(TbActorMsg msg) { | |
56 | 57 | switch (msg.getMsgType()) { |
57 | 58 | case TRANSPORT_TO_DEVICE_ACTOR_MSG: |
58 | - processor.process(context(), (TransportToDeviceActorMsgWrapper) msg); | |
59 | + processor.process(ctx, (TransportToDeviceActorMsgWrapper) msg); | |
59 | 60 | break; |
60 | 61 | case DEVICE_ATTRIBUTES_UPDATE_TO_DEVICE_ACTOR_MSG: |
61 | - processor.processAttributesUpdate(context(), (DeviceAttributesEventNotificationMsg) msg); | |
62 | + processor.processAttributesUpdate(ctx, (DeviceAttributesEventNotificationMsg) msg); | |
62 | 63 | break; |
63 | 64 | case DEVICE_CREDENTIALS_UPDATE_TO_DEVICE_ACTOR_MSG: |
64 | 65 | processor.processCredentialsUpdate(); |
... | ... | @@ -67,10 +68,10 @@ public class DeviceActor extends ContextAwareActor { |
67 | 68 | processor.processNameOrTypeUpdate((DeviceNameOrTypeUpdateMsg) msg); |
68 | 69 | break; |
69 | 70 | case DEVICE_RPC_REQUEST_TO_DEVICE_ACTOR_MSG: |
70 | - processor.processRpcRequest(context(), (ToDeviceRpcRequestActorMsg) msg); | |
71 | + processor.processRpcRequest(ctx, (ToDeviceRpcRequestActorMsg) msg); | |
71 | 72 | break; |
72 | 73 | case DEVICE_ACTOR_SERVER_SIDE_RPC_TIMEOUT_MSG: |
73 | - processor.processServerSideRpcTimeout(context(), (DeviceActorServerSideRpcTimeoutMsg) msg); | |
74 | + processor.processServerSideRpcTimeout(ctx, (DeviceActorServerSideRpcTimeoutMsg) msg); | |
74 | 75 | break; |
75 | 76 | case SESSION_TIMEOUT_MSG: |
76 | 77 | processor.checkSessionsTimeout(); | ... | ... |
... | ... | @@ -16,12 +16,14 @@ |
16 | 16 | package org.thingsboard.server.actors.device; |
17 | 17 | |
18 | 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 | 22 | import org.thingsboard.server.actors.service.ContextBasedCreator; |
20 | 23 | import org.thingsboard.server.common.data.id.DeviceId; |
21 | 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 | 28 | private final TenantId tenantId; |
27 | 29 | private final DeviceId deviceId; |
... | ... | @@ -33,7 +35,13 @@ public class DeviceActorCreator extends ContextBasedCreator<DeviceActor> { |
33 | 35 | } |
34 | 36 | |
35 | 37 | @Override |
36 | - public DeviceActor create() { | |
38 | + public TbActorId createActorId() { | |
39 | + return new TbEntityActorId(deviceId); | |
40 | + } | |
41 | + | |
42 | + @Override | |
43 | + public TbActor createActor() { | |
37 | 44 | return new DeviceActor(context, tenantId, deviceId); |
38 | 45 | } |
46 | + | |
39 | 47 | } | ... | ... |
... | ... | @@ -15,7 +15,6 @@ |
15 | 15 | */ |
16 | 16 | package org.thingsboard.server.actors.device; |
17 | 17 | |
18 | -import akka.actor.ActorContext; | |
19 | 18 | import com.google.common.util.concurrent.FutureCallback; |
20 | 19 | import com.google.common.util.concurrent.Futures; |
21 | 20 | import com.google.common.util.concurrent.ListenableFuture; |
... | ... | @@ -27,6 +26,7 @@ import org.thingsboard.rule.engine.api.RpcError; |
27 | 26 | import org.thingsboard.rule.engine.api.msg.DeviceAttributesEventNotificationMsg; |
28 | 27 | import org.thingsboard.rule.engine.api.msg.DeviceNameOrTypeUpdateMsg; |
29 | 28 | import org.thingsboard.server.actors.ActorSystemContext; |
29 | +import org.thingsboard.server.actors.TbActorCtx; | |
30 | 30 | import org.thingsboard.server.actors.shared.AbstractContextAwareMsgProcessor; |
31 | 31 | import org.thingsboard.server.common.data.Device; |
32 | 32 | import org.thingsboard.server.common.data.id.DeviceId; |
... | ... | @@ -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 | 131 | ToDeviceRpcRequest request = msg.getMsg(); |
132 | 132 | ToDeviceRpcRequestBody body = request.getBody(); |
133 | 133 | ToDeviceRpcRequestMsg rpcRequest = ToDeviceRpcRequestMsg.newBuilder().setRequestId( |
... | ... | @@ -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 | 166 | toDeviceRpcPendingMap.put(rpcRequest.getRequestId(), new ToDeviceRpcRequestMetadata(msg, sent)); |
167 | 167 | DeviceActorServerSideRpcTimeoutMsg timeoutMsg = new DeviceActorServerSideRpcTimeoutMsg(rpcRequest.getRequestId(), timeout); |
168 | 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 | 172 | ToDeviceRpcRequestMetadata requestMd = toDeviceRpcPendingMap.remove(msg.getId()); |
173 | 173 | if (requestMd != null) { |
174 | 174 | log.debug("[{}] RPC request [{}] timeout detected!", deviceId, msg.getId()); |
... | ... | @@ -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 | 181 | SessionType sessionType = getSessionType(sessionId); |
182 | 182 | if (!toDeviceRpcPendingMap.isEmpty()) { |
183 | 183 | log.debug("[{}] Pushing {} pending RPC messages to new async session [{}]", deviceId, toDeviceRpcPendingMap.size(), sessionId); |
... | ... | @@ -198,7 +198,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { |
198 | 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 | 202 | return entry -> { |
203 | 203 | ToDeviceRpcRequest request = entry.getValue().getMsg().getMsg(); |
204 | 204 | ToDeviceRpcRequestBody body = request.getBody(); |
... | ... | @@ -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 | 216 | TransportToDeviceActorMsg msg = wrapper.getMsg(); |
217 | 217 | TbCallback callback = wrapper.getCallback(); |
218 | 218 | if (msg.hasSessionEvent()) { |
... | ... | @@ -239,7 +239,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { |
239 | 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 | 243 | DeviceId deviceId = new DeviceId(new UUID(msg.getDeviceIdMSB(), msg.getDeviceIdLSB())); |
244 | 244 | systemContext.getClaimDevicesService().registerClaimingInfo(tenantId, deviceId, msg.getSecretKey(), msg.getDurationMs()); |
245 | 245 | } |
... | ... | @@ -252,7 +252,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { |
252 | 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 | 256 | int requestId = request.getRequestId(); |
257 | 257 | Futures.addCallback(getAttributesKvEntries(request), new FutureCallback<List<List<AttributeKvEntry>>>() { |
258 | 258 | @Override |
... | ... | @@ -310,7 +310,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { |
310 | 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 | 314 | if (attributeSubscriptions.size() > 0) { |
315 | 315 | boolean hasNotificationData = false; |
316 | 316 | AttributeUpdateNotificationMsg.Builder notification = AttributeUpdateNotificationMsg.newBuilder(); |
... | ... | @@ -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 | 353 | UUID sessionId = getSessionId(sessionInfo); |
354 | 354 | log.debug("[{}] Processing rpc command response [{}]", deviceId, sessionId); |
355 | 355 | ToDeviceRpcRequestMetadata requestMd = toDeviceRpcPendingMap.remove(responseMsg.getRequestId()); |
... | ... | @@ -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 | 366 | UUID sessionId = getSessionId(sessionInfo); |
367 | 367 | if (subscribeCmd.getUnsubscribe()) { |
368 | 368 | log.debug("[{}] Canceling attributes subscription for session [{}]", deviceId, sessionId); |
... | ... | @@ -383,7 +383,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { |
383 | 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 | 387 | UUID sessionId = getSessionId(sessionInfo); |
388 | 388 | if (subscribeCmd.getUnsubscribe()) { |
389 | 389 | log.debug("[{}] Canceling rpc subscription for session [{}]", deviceId, sessionId); |
... | ... | @@ -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 | 437 | UUID sessionId = getSessionId(sessionInfoProto); |
438 | 438 | SessionInfoMetaData sessionMD = sessions.computeIfAbsent(sessionId, |
439 | 439 | id -> new SessionInfoMetaData(new SessionInfo(SessionType.ASYNC, sessionInfoProto.getNodeId()), 0L)); |
... | ... | @@ -612,8 +612,8 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { |
612 | 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 | 619 | void checkSessionsTimeout() { | ... | ... |
... | ... | @@ -15,7 +15,6 @@ |
15 | 15 | */ |
16 | 16 | package org.thingsboard.server.actors.ruleChain; |
17 | 17 | |
18 | -import akka.actor.ActorRef; | |
19 | 18 | import com.datastax.driver.core.ResultSetFuture; |
20 | 19 | import com.fasterxml.jackson.core.JsonProcessingException; |
21 | 20 | import com.fasterxml.jackson.databind.ObjectMapper; |
... | ... | @@ -30,6 +29,7 @@ import org.thingsboard.rule.engine.api.ScriptEngine; |
30 | 29 | import org.thingsboard.rule.engine.api.TbContext; |
31 | 30 | import org.thingsboard.rule.engine.api.TbRelationTypes; |
32 | 31 | import org.thingsboard.server.actors.ActorSystemContext; |
32 | +import org.thingsboard.server.actors.TbActorRef; | |
33 | 33 | import org.thingsboard.server.common.data.Customer; |
34 | 34 | import org.thingsboard.server.common.data.DataConstants; |
35 | 35 | import org.thingsboard.server.common.data.Device; |
... | ... | @@ -40,6 +40,7 @@ import org.thingsboard.server.common.data.id.RuleChainId; |
40 | 40 | import org.thingsboard.server.common.data.id.RuleNodeId; |
41 | 41 | import org.thingsboard.server.common.data.id.TenantId; |
42 | 42 | import org.thingsboard.server.common.data.rule.RuleNode; |
43 | +import org.thingsboard.server.common.msg.TbActorMsg; | |
43 | 44 | import org.thingsboard.server.common.msg.TbMsg; |
44 | 45 | import org.thingsboard.server.common.msg.TbMsgMetaData; |
45 | 46 | import org.thingsboard.server.common.msg.queue.ServiceType; |
... | ... | @@ -64,7 +65,6 @@ import org.thingsboard.server.gen.transport.TransportProtos; |
64 | 65 | import org.thingsboard.server.queue.TbQueueCallback; |
65 | 66 | import org.thingsboard.server.queue.TbQueueMsgMetadata; |
66 | 67 | import org.thingsboard.server.service.script.RuleNodeJsScriptEngine; |
67 | -import scala.concurrent.duration.Duration; | |
68 | 68 | |
69 | 69 | import java.util.Collections; |
70 | 70 | import java.util.Set; |
... | ... | @@ -106,7 +106,7 @@ class DefaultTbContext implements TbContext { |
106 | 106 | if (nodeCtx.getSelf().isDebugMode()) { |
107 | 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 | 112 | @Override |
... | ... | @@ -132,7 +132,7 @@ class DefaultTbContext implements TbContext { |
132 | 132 | .setTenantIdMSB(getTenantId().getId().getMostSignificantBits()) |
133 | 133 | .setTenantIdLSB(getTenantId().getId().getLeastSignificantBits()) |
134 | 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 | 138 | @Override |
... | ... | @@ -189,7 +189,7 @@ class DefaultTbContext implements TbContext { |
189 | 189 | if (failureMessage != null) { |
190 | 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 | 195 | @Override |
... | ... | @@ -205,8 +205,8 @@ class DefaultTbContext implements TbContext { |
205 | 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 | 212 | @Override |
... | ... | @@ -215,7 +215,7 @@ class DefaultTbContext implements TbContext { |
215 | 215 | mainCtx.persistDebugOutput(nodeCtx.getTenantId(), nodeCtx.getSelf().getId(), msg, TbRelationTypes.FAILURE, th); |
216 | 216 | } |
217 | 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 | 221 | public void updateSelf(RuleNode self) { |
... | ... | @@ -223,8 +223,8 @@ class DefaultTbContext implements TbContext { |
223 | 223 | } |
224 | 224 | |
225 | 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 | 230 | @Override | ... | ... |
... | ... | @@ -15,9 +15,11 @@ |
15 | 15 | */ |
16 | 16 | package org.thingsboard.server.actors.ruleChain; |
17 | 17 | |
18 | -import akka.actor.OneForOneStrategy; | |
19 | -import akka.actor.SupervisorStrategy; | |
20 | 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 | 23 | import org.thingsboard.server.actors.service.ComponentActor; |
22 | 24 | import org.thingsboard.server.actors.service.ContextBasedCreator; |
23 | 25 | import org.thingsboard.server.common.data.id.RuleChainId; |
... | ... | @@ -27,18 +29,24 @@ import org.thingsboard.server.common.msg.TbActorMsg; |
27 | 29 | import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; |
28 | 30 | import org.thingsboard.server.common.msg.queue.PartitionChangeMsg; |
29 | 31 | import org.thingsboard.server.common.msg.queue.QueueToRuleEngineMsg; |
30 | -import scala.concurrent.duration.Duration; | |
31 | 32 | |
32 | 33 | public class RuleChainActor extends ComponentActor<RuleChainId, RuleChainActorMessageProcessor> { |
33 | 34 | |
35 | + private final RuleChain ruleChain; | |
36 | + | |
34 | 37 | private RuleChainActor(ActorSystemContext systemContext, TenantId tenantId, RuleChain ruleChain) { |
35 | 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 | 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 | 50 | switch (msg.getMsgType()) { |
43 | 51 | case COMPONENT_LIFE_CYCLE_MSG: |
44 | 52 | onComponentLifecycleMsg((ComponentLifecycleMsg) msg); |
... | ... | @@ -64,7 +72,7 @@ public class RuleChainActor extends ComponentActor<RuleChainId, RuleChainActorMe |
64 | 72 | return true; |
65 | 73 | } |
66 | 74 | |
67 | - public static class ActorCreator extends ContextBasedCreator<RuleChainActor> { | |
75 | + public static class ActorCreator extends ContextBasedCreator { | |
68 | 76 | private static final long serialVersionUID = 1L; |
69 | 77 | |
70 | 78 | private final TenantId tenantId; |
... | ... | @@ -77,7 +85,12 @@ public class RuleChainActor extends ComponentActor<RuleChainId, RuleChainActorMe |
77 | 85 | } |
78 | 86 | |
79 | 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 | 94 | return new RuleChainActor(context, tenantId, ruleChain); |
82 | 95 | } |
83 | 96 | } |
... | ... | @@ -87,13 +100,4 @@ public class RuleChainActor extends ComponentActor<RuleChainId, RuleChainActorMe |
87 | 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 | 15 | */ |
16 | 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 | 18 | import lombok.extern.slf4j.Slf4j; |
22 | 19 | import org.thingsboard.rule.engine.api.TbRelationTypes; |
23 | 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 | 24 | import org.thingsboard.server.actors.service.DefaultActorService; |
25 | 25 | import org.thingsboard.server.actors.shared.ComponentMsgProcessor; |
26 | 26 | import org.thingsboard.server.common.data.EntityType; |
... | ... | @@ -64,20 +64,21 @@ import java.util.stream.Collectors; |
64 | 64 | @Slf4j |
65 | 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 | 69 | private final Map<RuleNodeId, RuleNodeCtx> nodeActors; |
70 | 70 | private final Map<RuleNodeId, List<RuleNodeRelation>> nodeRoutes; |
71 | 71 | private final RuleChainService service; |
72 | 72 | private final TbClusterService clusterService; |
73 | 73 | private final EdgeService edgeService; |
74 | 74 | private String ruleChainName; |
75 | + | |
75 | 76 | private RuleNodeId firstId; |
76 | 77 | private RuleNodeCtx firstNode; |
77 | 78 | private boolean started; |
78 | 79 | |
79 | 80 | RuleChainActorMessageProcessor(TenantId tenantId, RuleChain ruleChain, ActorSystemContext systemContext |
80 | - , ActorRef parent, ActorRef self) { | |
81 | + , TbActorRef parent, TbActorRef self) { | |
81 | 82 | super(systemContext, tenantId, ruleChain.getId()); |
82 | 83 | this.ruleChainName = ruleChain.getName(); |
83 | 84 | this.parent = parent; |
... | ... | @@ -95,7 +96,7 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh |
95 | 96 | } |
96 | 97 | |
97 | 98 | @Override |
98 | - public void start(ActorContext context) { | |
99 | + public void start(TbActorCtx context) { | |
99 | 100 | if (!started) { |
100 | 101 | RuleChain ruleChain = service.findRuleChainById(tenantId, entityId); |
101 | 102 | if (ruleChain != null) { |
... | ... | @@ -105,7 +106,7 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh |
105 | 106 | // Creating and starting the actors; |
106 | 107 | for (RuleNode ruleNode : ruleNodeList) { |
107 | 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 | 110 | nodeActors.put(ruleNode.getId(), new RuleNodeCtx(tenantId, self, ruleNodeActor, ruleNode)); |
110 | 111 | } |
111 | 112 | initRoutes(ruleChain, ruleNodeList); |
... | ... | @@ -118,7 +119,7 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh |
118 | 119 | } |
119 | 120 | |
120 | 121 | @Override |
121 | - public void onUpdate(ActorContext context) { | |
122 | + public void onUpdate(TbActorCtx context) { | |
122 | 123 | RuleChain ruleChain = service.findRuleChainById(tenantId, entityId); |
123 | 124 | if (ruleChain != null) { |
124 | 125 | if (ruleChain.getType().equals(RuleChainType.CORE)) { |
... | ... | @@ -129,22 +130,22 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh |
129 | 130 | RuleNodeCtx existing = nodeActors.get(ruleNode.getId()); |
130 | 131 | if (existing == null) { |
131 | 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 | 134 | nodeActors.put(ruleNode.getId(), new RuleNodeCtx(tenantId, self, ruleNodeActor, ruleNode)); |
134 | 135 | } else { |
135 | 136 | log.trace("[{}][{}] Updating rule node [{}]: {}", entityId, ruleNode.getId(), ruleNode.getName(), ruleNode); |
136 | 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 | 150 | initRoutes(ruleChain, ruleNodeList); |
150 | 151 | } else if (ruleChain.getType().equals(RuleChainType.EDGE)) { |
... | ... | @@ -154,26 +155,23 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh |
154 | 155 | } |
155 | 156 | |
156 | 157 | @Override |
157 | - public void stop(ActorContext context) { | |
158 | + public void stop(TbActorCtx ctx) { | |
158 | 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 | 161 | nodeActors.clear(); |
161 | 162 | nodeRoutes.clear(); |
162 | - context.stop(self); | |
163 | 163 | started = false; |
164 | 164 | } |
165 | 165 | |
166 | 166 | @Override |
167 | 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 | 177 | private void initRoutes(RuleChain ruleChain, List<RuleNode> ruleNodeList) { |
... | ... | @@ -256,7 +254,7 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh |
256 | 254 | try { |
257 | 255 | checkActive(msg); |
258 | 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 | 258 | List<RuleNodeRelation> relations = nodeRoutes.get(originatorNodeId).stream() |
261 | 259 | .filter(r -> contains(relationTypes, r.getType())) |
262 | 260 | .collect(Collectors.toList()); |
... | ... | @@ -312,7 +310,7 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh |
312 | 310 | pushMsgToNode(nodeActors.get(new RuleNodeId(target.getId())), msg, fromRelationType); |
313 | 311 | break; |
314 | 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 | 314 | break; |
317 | 315 | } |
318 | 316 | } else { |
... | ... | @@ -343,7 +341,7 @@ public class RuleChainActorMessageProcessor extends ComponentMsgProcessor<RuleCh |
343 | 341 | |
344 | 342 | private void pushMsgToNode(RuleNodeCtx nodeCtx, TbMsg msg, String fromRelationType) { |
345 | 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 | 345 | } else { |
348 | 346 | log.error("[{}][{}] RuleNodeCtx is empty", entityId, ruleChainName); |
349 | 347 | msg.getCallback().onFailure(new RuleEngineException("Rule Node CTX is empty")); | ... | ... |
... | ... | @@ -15,21 +15,22 @@ |
15 | 15 | */ |
16 | 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 | 18 | import lombok.Getter; |
19 | +import lombok.extern.slf4j.Slf4j; | |
24 | 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 | 24 | import org.thingsboard.server.actors.service.ContextAwareActor; |
26 | 25 | import org.thingsboard.server.actors.service.DefaultActorService; |
26 | +import org.thingsboard.server.actors.tenant.TenantActor; | |
27 | 27 | import org.thingsboard.server.common.data.EntityType; |
28 | 28 | import org.thingsboard.server.common.data.id.EntityId; |
29 | 29 | import org.thingsboard.server.common.data.id.RuleChainId; |
30 | 30 | import org.thingsboard.server.common.data.id.TenantId; |
31 | 31 | import org.thingsboard.server.common.data.page.PageDataIterable; |
32 | 32 | import org.thingsboard.server.common.data.rule.RuleChain; |
33 | +import org.thingsboard.server.common.msg.TbActorMsg; | |
33 | 34 | import org.thingsboard.server.common.data.rule.RuleChainType; |
34 | 35 | import org.thingsboard.server.dao.rule.RuleChainService; |
35 | 36 | |
... | ... | @@ -38,20 +39,19 @@ import java.util.function.Function; |
38 | 39 | /** |
39 | 40 | * Created by ashvayka on 15.03.18. |
40 | 41 | */ |
42 | +@Slf4j | |
41 | 43 | public abstract class RuleChainManagerActor extends ContextAwareActor { |
42 | 44 | |
43 | 45 | protected final TenantId tenantId; |
44 | 46 | private final RuleChainService ruleChainService; |
45 | - private final BiMap<RuleChainId, ActorRef> actors; | |
46 | 47 | @Getter |
47 | 48 | protected RuleChain rootChain; |
48 | 49 | @Getter |
49 | - protected ActorRef rootChainActor; | |
50 | + protected TbActorRef rootChainActor; | |
50 | 51 | |
51 | 52 | public RuleChainManagerActor(ActorSystemContext systemContext, TenantId tenantId) { |
52 | 53 | super(systemContext); |
53 | 54 | this.tenantId = tenantId; |
54 | - this.actors = HashBiMap.create(); | |
55 | 55 | this.ruleChainService = systemContext.getRuleChainService(); |
56 | 56 | } |
57 | 57 | |
... | ... | @@ -59,46 +59,41 @@ public abstract class RuleChainManagerActor extends ContextAwareActor { |
59 | 59 | for (RuleChain ruleChain : new PageDataIterable<>(link -> ruleChainService.findTenantRuleChainsByType(tenantId, RuleChainType.CORE, link), ContextAwareActor.ENTITY_PACK_LIMIT)) { |
60 | 60 | RuleChainId ruleChainId = ruleChain.getId(); |
61 | 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 | 63 | visit(ruleChain, actorRef); |
65 | 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 | 69 | if (entity != null && entity.isRoot() && entity.getType().equals(RuleChainType.CORE)) { |
71 | 70 | rootChain = entity; |
72 | 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 | 90 | if (entityId.getEntityType() == EntityType.RULE_CHAIN) { |
91 | - target = getOrCreateActor(this.context(), (RuleChainId) entityId); | |
91 | + target = getOrCreateActor((RuleChainId) entityId); | |
92 | 92 | } |
93 | 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 | 15 | */ |
16 | 16 | package org.thingsboard.server.actors.ruleChain; |
17 | 17 | |
18 | +import lombok.extern.slf4j.Slf4j; | |
18 | 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 | 24 | import org.thingsboard.server.actors.service.ComponentActor; |
20 | 25 | import org.thingsboard.server.actors.service.ContextBasedCreator; |
21 | 26 | import org.thingsboard.server.common.data.id.RuleChainId; |
22 | 27 | import org.thingsboard.server.common.data.id.RuleNodeId; |
23 | 28 | import org.thingsboard.server.common.data.id.TenantId; |
29 | +import org.thingsboard.server.common.data.rule.RuleChain; | |
24 | 30 | import org.thingsboard.server.common.msg.TbActorMsg; |
25 | 31 | import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; |
26 | 32 | import org.thingsboard.server.common.msg.queue.PartitionChangeMsg; |
27 | 33 | |
34 | +@Slf4j | |
28 | 35 | public class RuleNodeActor extends ComponentActor<RuleNodeId, RuleNodeActorMessageProcessor> { |
29 | 36 | |
30 | 37 | private final String ruleChainName; |
31 | 38 | private final RuleChainId ruleChainId; |
39 | + private final RuleNodeId ruleNodeId; | |
32 | 40 | |
33 | 41 | private RuleNodeActor(ActorSystemContext systemContext, TenantId tenantId, RuleChainId ruleChainId, String ruleChainName, RuleNodeId ruleNodeId) { |
34 | 42 | super(systemContext, tenantId, ruleNodeId); |
35 | 43 | this.ruleChainName = ruleChainName; |
36 | 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 | 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 | 55 | switch (msg.getMsgType()) { |
44 | 56 | case COMPONENT_LIFE_CYCLE_MSG: |
45 | 57 | onComponentLifecycleMsg((ComponentLifecycleMsg) msg); |
... | ... | @@ -93,8 +105,7 @@ public class RuleNodeActor extends ComponentActor<RuleNodeId, RuleNodeActorMessa |
93 | 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 | 110 | private final TenantId tenantId; |
100 | 111 | private final RuleChainId ruleChainId; |
... | ... | @@ -111,7 +122,12 @@ public class RuleNodeActor extends ComponentActor<RuleNodeId, RuleNodeActorMessa |
111 | 122 | } |
112 | 123 | |
113 | 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 | 131 | return new RuleNodeActor(context, tenantId, ruleChainId, ruleChainName, ruleNodeId); |
116 | 132 | } |
117 | 133 | } | ... | ... |
application/src/main/java/org/thingsboard/server/actors/ruleChain/RuleNodeActorMessageProcessor.java
... | ... | @@ -15,11 +15,11 @@ |
15 | 15 | */ |
16 | 16 | package org.thingsboard.server.actors.ruleChain; |
17 | 17 | |
18 | -import akka.actor.ActorContext; | |
19 | -import akka.actor.ActorRef; | |
20 | 18 | import org.thingsboard.rule.engine.api.TbNode; |
21 | 19 | import org.thingsboard.rule.engine.api.TbNodeConfiguration; |
22 | 20 | import org.thingsboard.server.actors.ActorSystemContext; |
21 | +import org.thingsboard.server.actors.TbActorCtx; | |
22 | +import org.thingsboard.server.actors.TbActorRef; | |
23 | 23 | import org.thingsboard.server.actors.shared.ComponentMsgProcessor; |
24 | 24 | import org.thingsboard.server.common.data.id.RuleNodeId; |
25 | 25 | import org.thingsboard.server.common.data.id.TenantId; |
... | ... | @@ -34,13 +34,13 @@ import org.thingsboard.server.common.msg.queue.RuleNodeException; |
34 | 34 | public class RuleNodeActorMessageProcessor extends ComponentMsgProcessor<RuleNodeId> { |
35 | 35 | |
36 | 36 | private final String ruleChainName; |
37 | - private final ActorRef self; | |
37 | + private final TbActorRef self; | |
38 | 38 | private RuleNode ruleNode; |
39 | 39 | private TbNode tbNode; |
40 | 40 | private DefaultTbContext defaultCtx; |
41 | 41 | |
42 | 42 | RuleNodeActorMessageProcessor(TenantId tenantId, String ruleChainName, RuleNodeId ruleNodeId, ActorSystemContext systemContext |
43 | - , ActorRef parent, ActorRef self) { | |
43 | + , TbActorRef parent, TbActorRef self) { | |
44 | 44 | super(systemContext, tenantId, ruleNodeId); |
45 | 45 | this.ruleChainName = ruleChainName; |
46 | 46 | this.self = self; |
... | ... | @@ -49,7 +49,7 @@ public class RuleNodeActorMessageProcessor extends ComponentMsgProcessor<RuleNod |
49 | 49 | } |
50 | 50 | |
51 | 51 | @Override |
52 | - public void start(ActorContext context) throws Exception { | |
52 | + public void start(TbActorCtx context) throws Exception { | |
53 | 53 | tbNode = initComponent(ruleNode); |
54 | 54 | if (tbNode != null) { |
55 | 55 | state = ComponentLifecycleState.ACTIVE; |
... | ... | @@ -57,7 +57,7 @@ public class RuleNodeActorMessageProcessor extends ComponentMsgProcessor<RuleNod |
57 | 57 | } |
58 | 58 | |
59 | 59 | @Override |
60 | - public void onUpdate(ActorContext context) throws Exception { | |
60 | + public void onUpdate(TbActorCtx context) throws Exception { | |
61 | 61 | RuleNode newRuleNode = systemContext.getRuleChainService().findRuleNodeById(tenantId, entityId); |
62 | 62 | boolean restartRequired = state != ComponentLifecycleState.ACTIVE || |
63 | 63 | !(ruleNode.getType().equals(newRuleNode.getType()) && ruleNode.getConfiguration().equals(newRuleNode.getConfiguration())); |
... | ... | @@ -72,11 +72,11 @@ public class RuleNodeActorMessageProcessor extends ComponentMsgProcessor<RuleNod |
72 | 72 | } |
73 | 73 | |
74 | 74 | @Override |
75 | - public void stop(ActorContext context) { | |
75 | + public void stop(TbActorCtx context) { | |
76 | 76 | if (tbNode != null) { |
77 | 77 | tbNode.destroy(); |
78 | + state = ComponentLifecycleState.SUSPENDED; | |
78 | 79 | } |
79 | - context.stop(self); | |
80 | 80 | } |
81 | 81 | |
82 | 82 | @Override | ... | ... |
... | ... | @@ -15,9 +15,9 @@ |
15 | 15 | */ |
16 | 16 | package org.thingsboard.server.actors.ruleChain; |
17 | 17 | |
18 | -import akka.actor.ActorRef; | |
19 | 18 | import lombok.AllArgsConstructor; |
20 | 19 | import lombok.Data; |
20 | +import org.thingsboard.server.actors.TbActorRef; | |
21 | 21 | import org.thingsboard.server.common.data.id.TenantId; |
22 | 22 | import org.thingsboard.server.common.data.rule.RuleNode; |
23 | 23 | |
... | ... | @@ -28,7 +28,7 @@ import org.thingsboard.server.common.data.rule.RuleNode; |
28 | 28 | @AllArgsConstructor |
29 | 29 | final class RuleNodeCtx { |
30 | 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 | 33 | private RuleNode self; |
34 | 34 | } | ... | ... |
... | ... | @@ -15,19 +15,23 @@ |
15 | 15 | */ |
16 | 16 | package org.thingsboard.server.actors.service; |
17 | 17 | |
18 | -import akka.actor.ActorRef; | |
18 | +import lombok.extern.slf4j.Slf4j; | |
19 | 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 | 23 | import org.thingsboard.server.actors.shared.ComponentMsgProcessor; |
21 | 24 | import org.thingsboard.server.actors.stats.StatsPersistMsg; |
22 | 25 | import org.thingsboard.server.common.data.id.EntityId; |
23 | 26 | import org.thingsboard.server.common.data.id.TenantId; |
24 | 27 | import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; |
25 | -import org.thingsboard.server.common.msg.queue.PartitionChangeMsg; | |
26 | 28 | import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; |
29 | +import org.thingsboard.server.common.msg.queue.PartitionChangeMsg; | |
27 | 30 | |
28 | 31 | /** |
29 | 32 | * @author Andrew Shvayka |
30 | 33 | */ |
34 | +@Slf4j | |
31 | 35 | public abstract class ComponentActor<T extends EntityId, P extends ComponentMsgProcessor<T>> extends ContextAwareActor { |
32 | 36 | |
33 | 37 | private long lastPersistedErrorTs = 0L; |
... | ... | @@ -43,30 +47,34 @@ public abstract class ComponentActor<T extends EntityId, P extends ComponentMsgP |
43 | 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 | 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 | 60 | try { |
53 | 61 | log.debug("[{}][{}][{}] Starting processor.", tenantId, id, id.getEntityType()); |
54 | - processor.start(context()); | |
62 | + processor.start(ctx); | |
55 | 63 | logLifecycleEvent(ComponentLifecycleEvent.STARTED); |
56 | 64 | if (systemContext.isStatisticsEnabled()) { |
57 | 65 | scheduleStatsPersistTick(); |
58 | 66 | } |
59 | 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 | 69 | logAndPersist("OnStart", e, true); |
63 | 70 | logLifecycleEvent(ComponentLifecycleEvent.STARTED, e); |
71 | + throw new TbActorException("Failed to init actor", e); | |
64 | 72 | } |
65 | 73 | } |
66 | 74 | |
67 | 75 | private void scheduleStatsPersistTick() { |
68 | 76 | try { |
69 | - processor.scheduleStatsPersistTick(context(), systemContext.getStatisticsPersistFrequency()); | |
77 | + processor.scheduleStatsPersistTick(ctx, systemContext.getStatisticsPersistFrequency()); | |
70 | 78 | } catch (Exception e) { |
71 | 79 | log.error("[{}][{}] Failed to schedule statistics store message. No statistics is going to be stored: {}", tenantId, id, e.getMessage()); |
72 | 80 | logAndPersist("onScheduleStatsPersistMsg", e); |
... | ... | @@ -74,10 +82,12 @@ public abstract class ComponentActor<T extends EntityId, P extends ComponentMsgP |
74 | 82 | } |
75 | 83 | |
76 | 84 | @Override |
77 | - public void postStop() { | |
85 | + public void destroy() { | |
78 | 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 | 91 | logLifecycleEvent(ComponentLifecycleEvent.STOPPED); |
82 | 92 | } catch (Exception e) { |
83 | 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 | 101 | try { |
92 | 102 | switch (msg.getEvent()) { |
93 | 103 | case CREATED: |
94 | - processor.onCreated(context()); | |
104 | + processor.onCreated(ctx); | |
95 | 105 | break; |
96 | 106 | case UPDATED: |
97 | - processor.onUpdate(context()); | |
107 | + processor.onUpdate(ctx); | |
98 | 108 | break; |
99 | 109 | case ACTIVATED: |
100 | - processor.onActivate(context()); | |
110 | + processor.onActivate(ctx); | |
101 | 111 | break; |
102 | 112 | case SUSPENDED: |
103 | - processor.onSuspend(context()); | |
113 | + processor.onSuspend(ctx); | |
104 | 114 | break; |
105 | 115 | case DELETED: |
106 | - processor.onStop(context()); | |
116 | + processor.onStop(ctx); | |
117 | + ctx.stop(ctx.getSelf()); | |
107 | 118 | break; |
108 | 119 | default: |
109 | 120 | break; |
... | ... | @@ -125,7 +136,7 @@ public abstract class ComponentActor<T extends EntityId, P extends ComponentMsgP |
125 | 136 | |
126 | 137 | protected void onStatsPersistTick(EntityId entityId) { |
127 | 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 | 140 | resetStatsCounters(); |
130 | 141 | } catch (Exception e) { |
131 | 142 | logAndPersist("onStatsPersistTick", e); |
... | ... | @@ -149,11 +160,11 @@ public abstract class ComponentActor<T extends EntityId, P extends ComponentMsgP |
149 | 160 | errorsOccurred++; |
150 | 161 | String componentName = processor != null ? processor.getComponentName() : "Unknown"; |
151 | 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 | 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 | 169 | long ts = System.currentTimeMillis(); |
159 | 170 | if (ts - lastPersistedErrorTs > getErrorPersistFrequency()) { | ... | ... |
... | ... | @@ -15,17 +15,18 @@ |
15 | 15 | */ |
16 | 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 | 19 | import org.slf4j.Logger; |
21 | 20 | import org.slf4j.LoggerFactory; |
21 | +import org.thingsboard.server.actors.AbstractTbActor; | |
22 | 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 | 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 | 31 | public static final int ENTITY_PACK_LIMIT = 1024; |
31 | 32 | |
... | ... | @@ -37,27 +38,29 @@ public abstract class ContextAwareActor extends UntypedAbstractActor { |
37 | 38 | } |
38 | 39 | |
39 | 40 | @Override |
40 | - public void onReceive(Object msg) { | |
41 | + public boolean process(TbActorMsg msg) { | |
41 | 42 | if (log.isDebugEnabled()) { |
42 | 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 | 15 | */ |
16 | 16 | package org.thingsboard.server.actors.service; |
17 | 17 | |
18 | -import akka.japi.Creator; | |
19 | 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 | 23 | protected final transient ActorSystemContext context; |
26 | 24 | ... | ... |
... | ... | @@ -15,85 +15,121 @@ |
15 | 15 | */ |
16 | 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 | 18 | import lombok.extern.slf4j.Slf4j; |
23 | 19 | import org.springframework.beans.factory.annotation.Autowired; |
24 | 20 | import org.springframework.beans.factory.annotation.Value; |
25 | 21 | import org.springframework.boot.context.event.ApplicationReadyEvent; |
26 | 22 | import org.springframework.context.event.EventListener; |
27 | -import org.springframework.scheduling.annotation.Scheduled; | |
28 | 23 | import org.springframework.stereotype.Service; |
24 | +import org.thingsboard.common.util.ThingsBoardThreadFactory; | |
29 | 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 | 31 | import org.thingsboard.server.actors.app.AppActor; |
31 | 32 | import org.thingsboard.server.actors.app.AppInitMsg; |
32 | 33 | import org.thingsboard.server.actors.stats.StatsActor; |
33 | 34 | import org.thingsboard.server.common.msg.queue.PartitionChangeMsg; |
34 | 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 | 37 | import javax.annotation.PostConstruct; |
40 | 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 | 43 | @Service |
44 | 44 | @Slf4j |
45 | 45 | public class DefaultActorService implements ActorService { |
46 | 46 | |
47 | - private static final String ACTOR_SYSTEM_NAME = "Akka"; | |
48 | - | |
49 | 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 | 52 | @Autowired |
55 | 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 | 80 | @PostConstruct |
62 | 81 | public void initActorSystem() { |
63 | - log.info("Initializing Actor system."); | |
82 | + log.info("Initializing actor system."); | |
64 | 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 | 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 | 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 | 98 | actorContext.setStatsActor(statsActor); |
73 | 99 | |
74 | 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 | 115 | @EventListener(ApplicationReadyEvent.class) |
78 | 116 | public void onApplicationEvent(ApplicationReadyEvent applicationReadyEvent) { |
79 | 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 | 121 | @EventListener(PartitionChangeEvent.class) |
84 | 122 | public void onApplicationEvent(PartitionChangeEvent partitionChangeEvent) { |
85 | 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 | 127 | @PreDestroy |
90 | 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 | ... | ... |
application/src/main/java/org/thingsboard/server/actors/shared/AbstractContextAwareMsgProcessor.java
... | ... | @@ -15,18 +15,13 @@ |
15 | 15 | */ |
16 | 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 | 18 | import com.fasterxml.jackson.databind.ObjectMapper; |
23 | -import lombok.AllArgsConstructor; | |
24 | -import lombok.Data; | |
25 | 19 | import lombok.extern.slf4j.Slf4j; |
26 | 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 | 25 | import java.util.concurrent.TimeUnit; |
31 | 26 | |
32 | 27 | @Slf4j |
... | ... | @@ -40,31 +35,16 @@ public abstract class AbstractContextAwareMsgProcessor { |
40 | 35 | this.systemContext = systemContext; |
41 | 36 | } |
42 | 37 | |
43 | - private Scheduler getScheduler() { | |
38 | + private ScheduledExecutorService getScheduler() { | |
44 | 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 | 15 | */ |
16 | 16 | package org.thingsboard.server.actors.shared; |
17 | 17 | |
18 | -import akka.actor.ActorContext; | |
19 | 18 | import lombok.extern.slf4j.Slf4j; |
20 | 19 | import org.thingsboard.server.actors.ActorSystemContext; |
20 | +import org.thingsboard.server.actors.TbActorCtx; | |
21 | 21 | import org.thingsboard.server.actors.stats.StatsPersistTick; |
22 | 22 | import org.thingsboard.server.common.data.id.EntityId; |
23 | 23 | import org.thingsboard.server.common.data.id.TenantId; |
24 | 24 | import org.thingsboard.server.common.data.plugin.ComponentLifecycleState; |
25 | 25 | import org.thingsboard.server.common.msg.TbMsg; |
26 | 26 | import org.thingsboard.server.common.msg.queue.PartitionChangeMsg; |
27 | -import org.thingsboard.server.common.msg.queue.RuleEngineException; | |
28 | 27 | import org.thingsboard.server.common.msg.queue.RuleNodeException; |
29 | 28 | |
30 | 29 | @Slf4j |
... | ... | @@ -42,38 +41,38 @@ public abstract class ComponentMsgProcessor<T extends EntityId> extends Abstract |
42 | 41 | |
43 | 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 | 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 | 51 | start(context); |
53 | 52 | } |
54 | 53 | |
55 | - public void onUpdate(ActorContext context) throws Exception { | |
54 | + public void onUpdate(TbActorCtx context) throws Exception { | |
56 | 55 | restart(context); |
57 | 56 | } |
58 | 57 | |
59 | - public void onActivate(ActorContext context) throws Exception { | |
58 | + public void onActivate(TbActorCtx context) throws Exception { | |
60 | 59 | restart(context); |
61 | 60 | } |
62 | 61 | |
63 | - public void onSuspend(ActorContext context) throws Exception { | |
62 | + public void onSuspend(TbActorCtx context) throws Exception { | |
64 | 63 | stop(context); |
65 | 64 | } |
66 | 65 | |
67 | - public void onStop(ActorContext context) throws Exception { | |
66 | + public void onStop(TbActorCtx context) throws Exception { | |
68 | 67 | stop(context); |
69 | 68 | } |
70 | 69 | |
71 | - private void restart(ActorContext context) throws Exception { | |
70 | + private void restart(TbActorCtx context) throws Exception { | |
72 | 71 | stop(context); |
73 | 72 | start(context); |
74 | 73 | } |
75 | 74 | |
76 | - public void scheduleStatsPersistTick(ActorContext context, long statsPersistFrequency) { | |
75 | + public void scheduleStatsPersistTick(TbActorCtx context, long statsPersistFrequency) { | |
77 | 76 | schedulePeriodicMsgWithDelay(context, new StatsPersistTick(), statsPersistFrequency, statsPersistFrequency); |
78 | 77 | } |
79 | 78 | ... | ... |
... | ... | @@ -19,10 +19,15 @@ import com.fasterxml.jackson.databind.JsonNode; |
19 | 19 | import com.fasterxml.jackson.databind.ObjectMapper; |
20 | 20 | import lombok.extern.slf4j.Slf4j; |
21 | 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 | 26 | import org.thingsboard.server.actors.service.ContextAwareActor; |
23 | 27 | import org.thingsboard.server.actors.service.ContextBasedCreator; |
24 | 28 | import org.thingsboard.server.common.data.DataConstants; |
25 | 29 | import org.thingsboard.server.common.data.Event; |
30 | +import org.thingsboard.server.common.msg.MsgType; | |
26 | 31 | import org.thingsboard.server.common.msg.TbActorMsg; |
27 | 32 | |
28 | 33 | @Slf4j |
... | ... | @@ -35,24 +40,17 @@ public class StatsActor extends ContextAwareActor { |
35 | 40 | } |
36 | 41 | |
37 | 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 | 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 | 54 | Event event = new Event(); |
57 | 55 | event.setEntityId(msg.getEntityId()); |
58 | 56 | event.setTenantId(msg.getTenantId()); |
... | ... | @@ -65,15 +63,21 @@ public class StatsActor extends ContextAwareActor { |
65 | 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 | 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 | 79 | @Override |
76 | - public StatsActor create() { | |
80 | + public TbActor createActor() { | |
77 | 81 | return new StatsActor(context); |
78 | 82 | } |
79 | 83 | } | ... | ... |
... | ... | @@ -20,13 +20,21 @@ import lombok.Getter; |
20 | 20 | import lombok.ToString; |
21 | 21 | import org.thingsboard.server.common.data.id.EntityId; |
22 | 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 | 26 | @AllArgsConstructor |
25 | 27 | @Getter |
26 | 28 | @ToString |
27 | -public final class StatsPersistMsg { | |
29 | +public final class StatsPersistMsg implements TbActorMsg { | |
30 | + | |
28 | 31 | private long messagesProcessed; |
29 | 32 | private long errorsOccurred; |
30 | 33 | private TenantId tenantId; |
31 | 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 | 15 | */ |
16 | 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 | 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 | 28 | import org.thingsboard.server.actors.device.DeviceActorCreator; |
29 | 29 | import org.thingsboard.server.actors.ruleChain.RuleChainManagerActor; |
30 | 30 | import org.thingsboard.server.actors.service.ContextBasedCreator; |
... | ... | @@ -32,6 +32,7 @@ import org.thingsboard.server.actors.service.DefaultActorService; |
32 | 32 | import org.thingsboard.server.common.data.EntityType; |
33 | 33 | import org.thingsboard.server.common.data.Tenant; |
34 | 34 | import org.thingsboard.server.common.data.id.DeviceId; |
35 | +import org.thingsboard.server.common.data.id.EntityId; | |
35 | 36 | import org.thingsboard.server.common.data.id.RuleChainId; |
36 | 37 | import org.thingsboard.server.common.data.id.TenantId; |
37 | 38 | import org.thingsboard.server.common.data.rule.RuleChain; |
... | ... | @@ -46,32 +47,25 @@ import org.thingsboard.server.common.msg.queue.PartitionChangeMsg; |
46 | 47 | import org.thingsboard.server.common.msg.queue.QueueToRuleEngineMsg; |
47 | 48 | import org.thingsboard.server.common.msg.queue.RuleEngineException; |
48 | 49 | import org.thingsboard.server.common.msg.queue.ServiceType; |
49 | -import scala.concurrent.duration.Duration; | |
50 | 50 | |
51 | 51 | import java.util.List; |
52 | 52 | import java.util.Optional; |
53 | -import java.util.stream.Collectors; | |
54 | 53 | |
54 | +@Slf4j | |
55 | 55 | public class TenantActor extends RuleChainManagerActor { |
56 | 56 | |
57 | - private final BiMap<DeviceId, ActorRef> deviceActors; | |
58 | 57 | private boolean isRuleEngineForCurrentTenant; |
59 | 58 | private boolean isCore; |
60 | 59 | |
61 | 60 | private TenantActor(ActorSystemContext systemContext, TenantId tenantId) { |
62 | 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 | 64 | boolean cantFindTenant = false; |
72 | 65 | |
73 | 66 | @Override |
74 | - public void preStart() { | |
67 | + public void init(TbActorCtx ctx) throws TbActorException { | |
68 | + super.init(ctx); | |
75 | 69 | log.info("[{}] Starting tenant actor.", tenantId); |
76 | 70 | try { |
77 | 71 | Tenant tenant = systemContext.getTenantService().findTenantById(tenantId); |
... | ... | @@ -101,16 +95,18 @@ public class TenantActor extends RuleChainManagerActor { |
101 | 95 | } |
102 | 96 | } catch (Exception e) { |
103 | 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 | 103 | @Override |
108 | - public void postStop() { | |
104 | + public void destroy() { | |
109 | 105 | log.info("[{}] Stopping tenant actor.", tenantId); |
110 | 106 | } |
111 | 107 | |
112 | 108 | @Override |
113 | - protected boolean process(TbActorMsg msg) { | |
109 | + protected boolean doProcess(TbActorMsg msg) { | |
114 | 110 | if (cantFindTenant) { |
115 | 111 | log.info("[{}] Processing missing Tenant msg: {}", tenantId, msg); |
116 | 112 | if (msg.getMsgType().equals(MsgType.QUEUE_TO_RULE_ENGINE_MSG)) { |
... | ... | @@ -127,13 +123,13 @@ public class TenantActor extends RuleChainManagerActor { |
127 | 123 | //To Rule Chain Actors |
128 | 124 | broadcast(msg); |
129 | 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 | 134 | break; |
139 | 135 | case COMPONENT_LIFE_CYCLE_MSG: |
... | ... | @@ -143,12 +139,14 @@ public class TenantActor extends RuleChainManagerActor { |
143 | 139 | onQueueToRuleEngineMsg((QueueToRuleEngineMsg) msg); |
144 | 140 | break; |
145 | 141 | case TRANSPORT_TO_DEVICE_ACTOR_MSG: |
142 | + onToDeviceActorMsg((DeviceAwareMsg) msg, false); | |
143 | + break; | |
146 | 144 | case DEVICE_ATTRIBUTES_UPDATE_TO_DEVICE_ACTOR_MSG: |
147 | 145 | case DEVICE_CREDENTIALS_UPDATE_TO_DEVICE_ACTOR_MSG: |
148 | 146 | case DEVICE_NAME_OR_TYPE_UPDATE_TO_DEVICE_ACTOR_MSG: |
149 | 147 | case DEVICE_RPC_REQUEST_TO_DEVICE_ACTOR_MSG: |
150 | 148 | case SERVER_RPC_RESPONSE_TO_DEVICE_ACTOR_MSG: |
151 | - onToDeviceActorMsg((DeviceAwareMsg) msg); | |
149 | + onToDeviceActorMsg((DeviceAwareMsg) msg, true); | |
152 | 150 | break; |
153 | 151 | case RULE_CHAIN_TO_RULE_CHAIN_MSG: |
154 | 152 | onRuleChainMsg((RuleChainAwareMsg) msg); |
... | ... | @@ -159,8 +157,8 @@ public class TenantActor extends RuleChainManagerActor { |
159 | 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 | 164 | private void onQueueToRuleEngineMsg(QueueToRuleEngineMsg msg) { |
... | ... | @@ -171,16 +169,15 @@ public class TenantActor extends RuleChainManagerActor { |
171 | 169 | TbMsg tbMsg = msg.getTbMsg(); |
172 | 170 | if (tbMsg.getRuleChainId() == null) { |
173 | 171 | if (getRootChainActor() != null) { |
174 | - getRootChainActor().tell(msg, self()); | |
172 | + getRootChainActor().tell(msg); | |
175 | 173 | } else { |
176 | 174 | tbMsg.getCallback().onFailure(new RuleEngineException("No Root Rule Chain available!")); |
177 | 175 | log.info("[{}] No Root Chain: {}", tenantId, msg); |
178 | 176 | } |
179 | 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 | 181 | log.trace("Received message for non-existing rule chain: [{}]", tbMsg.getRuleChainId()); |
185 | 182 | //TODO: 3.1 Log it to dead letters queue; |
186 | 183 | tbMsg.getCallback().onSuccess(); |
... | ... | @@ -189,19 +186,24 @@ public class TenantActor extends RuleChainManagerActor { |
189 | 186 | } |
190 | 187 | |
191 | 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 | 193 | if (!isCore) { |
197 | 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 | 204 | private void onComponentLifecycleMsg(ComponentLifecycleMsg msg) { |
203 | 205 | if (isRuleEngineForCurrentTenant) { |
204 | - ActorRef target = getEntityActorRef(msg.getEntityId()); | |
206 | + TbActorRef target = getEntityActorRef(msg.getEntityId()); | |
205 | 207 | if (target != null) { |
206 | 208 | if (msg.getEntityId().getEntityType() == EntityType.RULE_CHAIN) { |
207 | 209 | RuleChain ruleChain = systemContext.getRuleChainService(). |
... | ... | @@ -210,42 +212,20 @@ public class TenantActor extends RuleChainManagerActor { |
210 | 212 | visit(ruleChain, target); |
211 | 213 | } |
212 | 214 | } |
213 | - target.tell(msg, ActorRef.noSender()); | |
215 | + target.tellWithHighPriority(msg); | |
214 | 216 | } else { |
215 | 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 | 230 | private final TenantId tenantId; |
251 | 231 | |
... | ... | @@ -255,18 +235,14 @@ public class TenantActor extends RuleChainManagerActor { |
255 | 235 | } |
256 | 236 | |
257 | 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 | 15 | */ |
16 | 16 | package org.thingsboard.server.service.queue; |
17 | 17 | |
18 | -import akka.actor.ActorRef; | |
19 | 18 | import lombok.extern.slf4j.Slf4j; |
20 | 19 | import org.springframework.beans.factory.annotation.Value; |
21 | 20 | import org.springframework.scheduling.annotation.Scheduled; |
... | ... | @@ -157,7 +156,7 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService<ToCore |
157 | 156 | tbCoreDeviceRpcService.forwardRpcRequestToDeviceActor((ToDeviceRpcRequestActorMsg) tbActorMsg); |
158 | 157 | } else { |
159 | 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 | 162 | callback.onSuccess(); |
... | ... | @@ -168,7 +167,7 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService<ToCore |
168 | 167 | } |
169 | 168 | }); |
170 | 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 | 171 | ctx.getFailedMap().forEach((id, msg) -> log.warn("[{}] Failed to process message: {}", id, msg.getValue())); |
173 | 172 | } |
174 | 173 | mainConsumer.commit(); |
... | ... | @@ -215,7 +214,7 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService<ToCore |
215 | 214 | Optional<TbActorMsg> actorMsg = encodingService.decode(toCoreNotification.getComponentLifecycleMsg().toByteArray()); |
216 | 215 | if (actorMsg.isPresent()) { |
217 | 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 | 219 | callback.onSuccess(); |
221 | 220 | } |
... | ... | @@ -293,7 +292,7 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService<ToCore |
293 | 292 | if (statsEnabled) { |
294 | 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 | 298 | private void throwNotHandled(Object msg, TbCallback callback) { | ... | ... |
... | ... | @@ -15,7 +15,6 @@ |
15 | 15 | */ |
16 | 16 | package org.thingsboard.server.service.queue; |
17 | 17 | |
18 | -import akka.actor.ActorRef; | |
19 | 18 | import com.google.protobuf.ProtocolStringList; |
20 | 19 | import lombok.extern.slf4j.Slf4j; |
21 | 20 | import org.springframework.beans.factory.annotation.Value; |
... | ... | @@ -51,7 +50,6 @@ import org.thingsboard.server.service.queue.processing.TbRuleEngineProcessingStr |
51 | 50 | import org.thingsboard.server.service.queue.processing.TbRuleEngineSubmitStrategy; |
52 | 51 | import org.thingsboard.server.service.queue.processing.TbRuleEngineSubmitStrategyFactory; |
53 | 52 | import org.thingsboard.server.service.rpc.FromDeviceRpcResponse; |
54 | -import org.thingsboard.server.service.rpc.TbCoreDeviceRpcService; | |
55 | 53 | import org.thingsboard.server.service.rpc.TbRuleEngineDeviceRpcService; |
56 | 54 | import org.thingsboard.server.service.stats.RuleEngineStatisticsService; |
57 | 55 | |
... | ... | @@ -168,7 +166,7 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService< |
168 | 166 | TbMsgCallback callback = new TbMsgPackCallback(id, tenantId, ctx); |
169 | 167 | try { |
170 | 168 | if (toRuleEngineMsg.getTbMsg() != null && !toRuleEngineMsg.getTbMsg().isEmpty()) { |
171 | - forwardToRuleEngineActor(tenantId, toRuleEngineMsg, callback); | |
169 | + forwardToRuleEngineActor(configuration.getName(), tenantId, toRuleEngineMsg, callback); | |
172 | 170 | } else { |
173 | 171 | callback.onSuccess(); |
174 | 172 | } |
... | ... | @@ -182,7 +180,7 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService< |
182 | 180 | timeout = true; |
183 | 181 | } |
184 | 182 | |
185 | - TbRuleEngineProcessingResult result = new TbRuleEngineProcessingResult(timeout, ctx); | |
183 | + TbRuleEngineProcessingResult result = new TbRuleEngineProcessingResult(configuration.getName(), timeout, ctx); | |
186 | 184 | TbRuleEngineProcessingDecision decision = ackStrategy.analyze(result); |
187 | 185 | if (statsEnabled) { |
188 | 186 | stats.log(result, decision.isCommit()); |
... | ... | @@ -232,7 +230,7 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService< |
232 | 230 | Optional<TbActorMsg> actorMsg = encodingService.decode(nfMsg.getComponentLifecycleMsg().toByteArray()); |
233 | 231 | if (actorMsg.isPresent()) { |
234 | 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 | 235 | callback.onSuccess(); |
238 | 236 | } else if (nfMsg.hasFromDeviceRpcResponse()) { |
... | ... | @@ -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 | 251 | QueueToRuleEngineMsg msg; |
254 | 252 | ProtocolStringList relationTypesList = toRuleEngineMsg.getRelationTypesList(); |
255 | 253 | Set<String> relationTypes = null; |
... | ... | @@ -261,7 +259,7 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService< |
261 | 259 | } |
262 | 260 | } |
263 | 261 | msg = new QueueToRuleEngineMsg(tenantId, tbMsg, relationTypes, toRuleEngineMsg.getFailureMessage()); |
264 | - actorContext.tell(msg, ActorRef.noSender()); | |
262 | + actorContext.tell(msg); | |
265 | 263 | } |
266 | 264 | |
267 | 265 | @Scheduled(fixedDelayString = "${queue.rule-engine.stats.print-interval-ms}") | ... | ... |
... | ... | @@ -28,13 +28,16 @@ import java.util.concurrent.ConcurrentMap; |
28 | 28 | public class TbRuleEngineProcessingResult { |
29 | 29 | |
30 | 30 | @Getter |
31 | + private final String queueName; | |
32 | + @Getter | |
31 | 33 | private final boolean success; |
32 | 34 | @Getter |
33 | 35 | private final boolean timeout; |
34 | 36 | @Getter |
35 | 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 | 41 | this.timeout = timeout; |
39 | 42 | this.ctx = ctx; |
40 | 43 | this.success = !timeout && ctx.getPendingMap().isEmpty() && ctx.getFailedMap().isEmpty(); | ... | ... |
... | ... | @@ -100,7 +100,7 @@ public class TbRuleEngineProcessingStrategyFactory { |
100 | 100 | } |
101 | 101 | log.debug("[{}] Going to reprocess {} messages", queueName, toReprocess.size()); |
102 | 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 | 105 | if (pauseBetweenRetries > 0) { |
106 | 106 | try { |
... | ... | @@ -129,10 +129,10 @@ public class TbRuleEngineProcessingStrategyFactory { |
129 | 129 | log.debug("[{}] Reprocessing skipped for {} failed and {} timeout messages", queueName, result.getFailedMap().size(), result.getPendingMap().size()); |
130 | 130 | } |
131 | 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 | 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 | 137 | return new TbRuleEngineProcessingDecision(true, null); |
138 | 138 | } | ... | ... |
... | ... | @@ -15,7 +15,6 @@ |
15 | 15 | */ |
16 | 16 | package org.thingsboard.server.service.rpc; |
17 | 17 | |
18 | -import akka.actor.ActorRef; | |
19 | 18 | import com.fasterxml.jackson.core.JsonProcessingException; |
20 | 19 | import com.fasterxml.jackson.databind.ObjectMapper; |
21 | 20 | import com.fasterxml.jackson.databind.node.ObjectNode; |
... | ... | @@ -122,7 +121,7 @@ public class DefaultTbCoreDeviceRpcService implements TbCoreDeviceRpcService { |
122 | 121 | log.trace("[{}][{}] Processing local rpc call to device actor [{}]", request.getTenantId(), request.getId(), request.getDeviceId()); |
123 | 122 | UUID requestId = request.getId(); |
124 | 123 | localToDeviceRpcRequests.put(requestId, rpcMsg); |
125 | - actorContext.tell(rpcMsg, ActorRef.noSender()); | |
124 | + actorContext.tellWithHighPriority(rpcMsg); | |
126 | 125 | scheduleToDeviceTimeout(request, requestId); |
127 | 126 | } |
128 | 127 | |
... | ... | @@ -176,7 +175,7 @@ public class DefaultTbCoreDeviceRpcService implements TbCoreDeviceRpcService { |
176 | 175 | } |
177 | 176 | |
178 | 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 | 179 | log.trace("[{}] processing to rule engine request.", requestId); |
181 | 180 | scheduler.schedule(() -> { |
182 | 181 | log.trace("[{}] timeout for processing to rule engine request.", requestId); |
... | ... | @@ -188,7 +187,7 @@ public class DefaultTbCoreDeviceRpcService implements TbCoreDeviceRpcService { |
188 | 187 | } |
189 | 188 | |
190 | 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 | 191 | log.trace("[{}] processing to device request.", requestId); |
193 | 192 | scheduler.schedule(() -> { |
194 | 193 | log.trace("[{}] timeout for to device request.", requestId); | ... | ... |
... | ... | @@ -164,7 +164,7 @@ public class DefaultTbRuleEngineRpcService implements TbRuleEngineDeviceRpcServi |
164 | 164 | } |
165 | 165 | |
166 | 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 | 168 | log.trace("[{}] processing the request: [{}]", this.hashCode(), requestId); |
169 | 169 | scheduler.schedule(() -> { |
170 | 170 | log.trace("[{}] timeout the request: [{}]", this.hashCode(), requestId); | ... | ... |
... | ... | @@ -126,7 +126,7 @@ public abstract class AbstractNashornJsInvokeService extends AbstractJsInvokeSer |
126 | 126 | scriptIdToNameMap.put(scriptId, functionName); |
127 | 127 | return scriptId; |
128 | 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 | 130 | throw new ExecutionException(e); |
131 | 131 | } |
132 | 132 | }); | ... | ... |
application/src/main/resources/actor-system.conf
deleted
100644 → 0
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 | 27 | |
28 | 28 | <logger name="org.thingsboard.server" level="INFO" /> |
29 | 29 | <logger name="org.thingsboard.server.service.edge" level="TRACE" /> |
30 | - <logger name="akka" level="INFO" /> | |
31 | 30 | |
32 | 31 | <!-- <logger name="org.thingsboard.server.service.queue" level="TRACE" />--> |
33 | 32 | <!-- <logger name="org.thingsboard.server.service.transport" level="TRACE" />--> | ... | ... |
... | ... | @@ -281,6 +281,14 @@ sql: |
281 | 281 | |
282 | 282 | # Actor system parameters |
283 | 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 | 292 | tenant: |
285 | 293 | create_components_on_init: "${ACTORS_TENANT_CREATE_COMPONENTS_ON_INIT:true}" |
286 | 294 | session: |
... | ... | @@ -318,11 +326,6 @@ actors: |
318 | 326 | enabled: "${ACTORS_STATISTICS_ENABLED:true}" |
319 | 327 | js_print_interval_ms: "${ACTORS_JS_STATISTICS_PRINT_INTERVAL_MS:10000}" |
320 | 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 | 330 | cache: |
328 | 331 | # caffeine or redis | ... | ... |
... | ... | @@ -26,7 +26,9 @@ import java.util.Arrays; |
26 | 26 | |
27 | 27 | @RunWith(ClasspathSuite.class) |
28 | 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 | 32 | public class MqttSqlTestSuite { |
31 | 33 | |
32 | 34 | @ClassRule | ... | ... |
... | ... | @@ -136,7 +136,7 @@ public abstract class AbstractMqttServerSideRpcIntegrationTest extends AbstractC |
136 | 136 | String setGpioRequest = "{\"method\":\"setGpio\",\"params\":{\"pin\": \"24\",\"value\": 1},\"timeout\": 6000}"; |
137 | 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 | 140 | asyncContextTimeoutToUseRpcPlugin); |
141 | 141 | } |
142 | 142 | |
... | ... | @@ -193,7 +193,7 @@ public abstract class AbstractMqttServerSideRpcIntegrationTest extends AbstractC |
193 | 193 | String setGpioRequest = "{\"method\":\"setGpio\",\"params\":{\"pin\": \"27\",\"value\": 1},\"timeout\": 6000}"; |
194 | 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 | 197 | asyncContextTimeoutToUseRpcPlugin); |
198 | 198 | } |
199 | 199 | ... | ... |
... | ... | @@ -15,8 +15,6 @@ |
15 | 15 | */ |
16 | 16 | package org.thingsboard.server.rules.flow; |
17 | 17 | |
18 | -import akka.actor.ActorRef; | |
19 | -import com.datastax.driver.core.utils.UUIDs; | |
20 | 18 | import lombok.extern.slf4j.Slf4j; |
21 | 19 | import org.junit.After; |
22 | 20 | import org.junit.Assert; |
... | ... | @@ -26,7 +24,6 @@ import org.mockito.Mockito; |
26 | 24 | import org.springframework.beans.factory.annotation.Autowired; |
27 | 25 | import org.thingsboard.rule.engine.metadata.TbGetAttributesNodeConfiguration; |
28 | 26 | import org.thingsboard.server.actors.ActorSystemContext; |
29 | -import org.thingsboard.server.actors.service.ActorService; | |
30 | 27 | import org.thingsboard.server.common.data.*; |
31 | 28 | import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry; |
32 | 29 | import org.thingsboard.server.common.data.kv.StringDataEntry; |
... | ... | @@ -36,7 +33,6 @@ import org.thingsboard.server.common.data.rule.RuleChainMetaData; |
36 | 33 | import org.thingsboard.server.common.data.rule.RuleNode; |
37 | 34 | import org.thingsboard.server.common.data.security.Authority; |
38 | 35 | import org.thingsboard.server.common.msg.TbMsg; |
39 | -import org.thingsboard.server.common.msg.TbMsgDataType; | |
40 | 36 | import org.thingsboard.server.common.msg.TbMsgMetaData; |
41 | 37 | import org.thingsboard.server.common.msg.queue.QueueToRuleEngineMsg; |
42 | 38 | import org.thingsboard.server.common.msg.queue.TbMsgCallback; |
... | ... | @@ -151,7 +147,7 @@ public abstract class AbstractRuleEngineFlowIntegrationTest extends AbstractRule |
151 | 147 | TbMsg tbMsg = TbMsg.newMsg("CUSTOM", device.getId(), new TbMsgMetaData(), "{}", tbMsgCallback); |
152 | 148 | QueueToRuleEngineMsg qMsg = new QueueToRuleEngineMsg(savedTenant.getId(), tbMsg, null, null); |
153 | 149 | // Pushing Message to the system |
154 | - actorSystem.tell(qMsg, ActorRef.noSender()); | |
150 | + actorSystem.tell(qMsg); | |
155 | 151 | Mockito.verify(tbMsgCallback, Mockito.timeout(10000)).onSuccess(); |
156 | 152 | |
157 | 153 | TimePageData<Event> eventsPage = getDebugEvents(savedTenant.getId(), ruleChain.getFirstRuleNodeId(), 1000); |
... | ... | @@ -263,7 +259,7 @@ public abstract class AbstractRuleEngineFlowIntegrationTest extends AbstractRule |
263 | 259 | TbMsg tbMsg = TbMsg.newMsg("CUSTOM", device.getId(), new TbMsgMetaData(), "{}", tbMsgCallback); |
264 | 260 | QueueToRuleEngineMsg qMsg = new QueueToRuleEngineMsg(savedTenant.getId(), tbMsg, null, null); |
265 | 261 | // Pushing Message to the system |
266 | - actorSystem.tell(qMsg, ActorRef.noSender()); | |
262 | + actorSystem.tell(qMsg); | |
267 | 263 | |
268 | 264 | Mockito.verify(tbMsgCallback, Mockito.timeout(10000)).onSuccess(); |
269 | 265 | ... | ... |
... | ... | @@ -15,8 +15,6 @@ |
15 | 15 | */ |
16 | 16 | package org.thingsboard.server.rules.lifecycle; |
17 | 17 | |
18 | -import akka.actor.ActorRef; | |
19 | -import com.datastax.driver.core.utils.UUIDs; | |
20 | 18 | import lombok.extern.slf4j.Slf4j; |
21 | 19 | import org.junit.After; |
22 | 20 | import org.junit.Assert; |
... | ... | @@ -26,7 +24,6 @@ import org.mockito.Mockito; |
26 | 24 | import org.springframework.beans.factory.annotation.Autowired; |
27 | 25 | import org.thingsboard.rule.engine.metadata.TbGetAttributesNodeConfiguration; |
28 | 26 | import org.thingsboard.server.actors.ActorSystemContext; |
29 | -import org.thingsboard.server.actors.service.ActorService; | |
30 | 27 | import org.thingsboard.server.common.data.DataConstants; |
31 | 28 | import org.thingsboard.server.common.data.Device; |
32 | 29 | import org.thingsboard.server.common.data.Event; |
... | ... | @@ -40,7 +37,6 @@ import org.thingsboard.server.common.data.rule.RuleChainMetaData; |
40 | 37 | import org.thingsboard.server.common.data.rule.RuleNode; |
41 | 38 | import org.thingsboard.server.common.data.security.Authority; |
42 | 39 | import org.thingsboard.server.common.msg.TbMsg; |
43 | -import org.thingsboard.server.common.msg.TbMsgDataType; | |
44 | 40 | import org.thingsboard.server.common.msg.TbMsgMetaData; |
45 | 41 | import org.thingsboard.server.common.msg.queue.QueueToRuleEngineMsg; |
46 | 42 | import org.thingsboard.server.common.msg.queue.TbMsgCallback; |
... | ... | @@ -142,7 +138,7 @@ public abstract class AbstractRuleEngineLifecycleIntegrationTest extends Abstrac |
142 | 138 | TbMsg tbMsg = TbMsg.newMsg("CUSTOM", device.getId(), new TbMsgMetaData(), "{}", tbMsgCallback); |
143 | 139 | QueueToRuleEngineMsg qMsg = new QueueToRuleEngineMsg(savedTenant.getId(), tbMsg, null, null); |
144 | 140 | // Pushing Message to the system |
145 | - actorSystem.tell(qMsg, ActorRef.noSender()); | |
141 | + actorSystem.tell(qMsg); | |
146 | 142 | Mockito.verify(tbMsgCallback, Mockito.timeout(3000)).onSuccess(); |
147 | 143 | |
148 | 144 | ... | ... |
common/actor/pom.xml
0 → 100644
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 | +} | ... | ... |
common/actor/src/main/java/org/thingsboard/server/actors/TbActorNotRegisteredException.java
0 → 100644
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 | +} | ... | ... |
common/actor/src/test/resources/logback.xml
0 → 100644
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 | 20 | <modelVersion>4.0.0</modelVersion> |
21 | 21 | <parent> |
22 | 22 | <groupId>org.thingsboard</groupId> |
23 | - <version>2.5.1-SNAPSHOT</version> | |
23 | + <version>2.5.3-SNAPSHOT</version> | |
24 | 24 | <artifactId>common</artifactId> |
25 | 25 | </parent> |
26 | 26 | <groupId>org.thingsboard.common</groupId> | ... | ... |
... | ... | @@ -20,7 +20,7 @@ |
20 | 20 | <modelVersion>4.0.0</modelVersion> |
21 | 21 | <parent> |
22 | 22 | <groupId>org.thingsboard</groupId> |
23 | - <version>2.5.1-SNAPSHOT</version> | |
23 | + <version>2.5.3-SNAPSHOT</version> | |
24 | 24 | <artifactId>common</artifactId> |
25 | 25 | </parent> |
26 | 26 | <groupId>org.thingsboard.common</groupId> | ... | ... |
... | ... | @@ -20,7 +20,7 @@ |
20 | 20 | <modelVersion>4.0.0</modelVersion> |
21 | 21 | <parent> |
22 | 22 | <groupId>org.thingsboard</groupId> |
23 | - <version>2.5.1-SNAPSHOT</version> | |
23 | + <version>2.5.3-SNAPSHOT</version> | |
24 | 24 | <artifactId>common</artifactId> |
25 | 25 | </parent> |
26 | 26 | <groupId>org.thingsboard.common</groupId> | ... | ... |
... | ... | @@ -20,7 +20,7 @@ |
20 | 20 | <modelVersion>4.0.0</modelVersion> |
21 | 21 | <parent> |
22 | 22 | <groupId>org.thingsboard</groupId> |
23 | - <version>2.5.1-SNAPSHOT</version> | |
23 | + <version>2.5.3-SNAPSHOT</version> | |
24 | 24 | <artifactId>common</artifactId> |
25 | 25 | </parent> |
26 | 26 | <groupId>org.thingsboard.common</groupId> | ... | ... |
... | ... | @@ -21,7 +21,6 @@ import org.thingsboard.server.common.msg.queue.QueueToRuleEngineMsg; |
21 | 21 | /** |
22 | 22 | * Created by ashvayka on 15.03.18. |
23 | 23 | */ |
24 | -//TODO: add all "See" references | |
25 | 24 | public enum MsgType { |
26 | 25 | |
27 | 26 | /** |
... | ... | @@ -97,6 +96,7 @@ public enum MsgType { |
97 | 96 | |
98 | 97 | STATS_PERSIST_TICK_MSG, |
99 | 98 | |
99 | + STATS_PERSIST_MSG, | |
100 | 100 | |
101 | 101 | /** |
102 | 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 | 25 | import org.thingsboard.server.common.data.id.RuleChainId; |
26 | 26 | import org.thingsboard.server.common.data.id.RuleNodeId; |
27 | 27 | import org.thingsboard.server.common.msg.gen.MsgProtos; |
28 | +import org.thingsboard.server.common.msg.queue.ServiceQueue; | |
28 | 29 | import org.thingsboard.server.common.msg.queue.TbMsgCallback; |
29 | 30 | |
30 | 31 | import java.io.IOException; |
... | ... | @@ -39,6 +40,7 @@ import java.util.UUID; |
39 | 40 | @Slf4j |
40 | 41 | public final class TbMsg implements Serializable { |
41 | 42 | |
43 | + private final String queueName; | |
42 | 44 | private final UUID id; |
43 | 45 | private final long ts; |
44 | 46 | private final String type; |
... | ... | @@ -51,39 +53,44 @@ public final class TbMsg implements Serializable { |
51 | 53 | //This field is not serialized because we use queues and there is no need to do it |
52 | 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 | 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 | 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 | 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 | 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 | 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 | 82 | data, origMsg.getRuleChainId(), origMsg.getRuleNodeId(), origMsg.getCallback()); |
77 | 83 | } |
78 | 84 | |
79 | 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 | 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 | 91 | RuleChainId ruleChainId, RuleNodeId ruleNodeId, TbMsgCallback callback) { |
86 | 92 | this.id = id; |
93 | + this.queueName = queueName; | |
87 | 94 | if (ts > 0) { |
88 | 95 | this.ts = ts; |
89 | 96 | } else { |
... | ... | @@ -136,7 +143,7 @@ public final class TbMsg implements Serializable { |
136 | 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 | 147 | try { |
141 | 148 | MsgProtos.TbMsgProto proto = MsgProtos.TbMsgProto.parseFrom(data); |
142 | 149 | TbMsgMetaData metaData = new TbMsgMetaData(proto.getMetaData().getDataMap()); |
... | ... | @@ -150,18 +157,18 @@ public final class TbMsg implements Serializable { |
150 | 157 | ruleNodeId = new RuleNodeId(new UUID(proto.getRuleNodeIdMSB(), proto.getRuleNodeIdLSB())); |
151 | 158 | } |
152 | 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 | 161 | } catch (InvalidProtocolBufferException e) { |
155 | 162 | throw new IllegalStateException("Could not parse protobuf for TbMsg", e); |
156 | 163 | } |
157 | 164 | } |
158 | 165 | |
159 | 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 | 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 | 174 | public TbMsgCallback getCallback() { |
... | ... | @@ -172,4 +179,8 @@ public final class TbMsg implements Serializable { |
172 | 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 | 16 | package org.thingsboard.server.common.msg.aware; |
17 | 17 | |
18 | 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 | 23 | DeviceId getDeviceId(); |
23 | 24 | } | ... | ... |
... | ... | @@ -16,8 +16,9 @@ |
16 | 16 | package org.thingsboard.server.common.msg.aware; |
17 | 17 | |
18 | 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 | 23 | RuleChainId getRuleChainId(); |
23 | 24 | ... | ... |
... | ... | @@ -16,8 +16,9 @@ |
16 | 16 | package org.thingsboard.server.common.msg.aware; |
17 | 17 | |
18 | 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 | 23 | TenantId getTenantId(); |
23 | 24 | ... | ... |
... | ... | @@ -20,7 +20,7 @@ |
20 | 20 | <modelVersion>4.0.0</modelVersion> |
21 | 21 | <parent> |
22 | 22 | <groupId>org.thingsboard</groupId> |
23 | - <version>2.5.1-SNAPSHOT</version> | |
23 | + <version>2.5.3-SNAPSHOT</version> | |
24 | 24 | <artifactId>thingsboard</artifactId> |
25 | 25 | </parent> |
26 | 26 | <artifactId>common</artifactId> |
... | ... | @@ -37,6 +37,7 @@ |
37 | 37 | <module>data</module> |
38 | 38 | <module>util</module> |
39 | 39 | <module>message</module> |
40 | + <module>actor</module> | |
40 | 41 | <module>queue</module> |
41 | 42 | <module>transport</module> |
42 | 43 | <module>dao-api</module> | ... | ... |
... | ... | @@ -20,7 +20,7 @@ |
20 | 20 | <modelVersion>4.0.0</modelVersion> |
21 | 21 | <parent> |
22 | 22 | <groupId>org.thingsboard</groupId> |
23 | - <version>2.5.1-SNAPSHOT</version> | |
23 | + <version>2.5.3-SNAPSHOT</version> | |
24 | 24 | <artifactId>common</artifactId> |
25 | 25 | </parent> |
26 | 26 | <groupId>org.thingsboard.common</groupId> | ... | ... |
... | ... | @@ -91,8 +91,6 @@ public class DefaultTbQueueRequestTemplate<Request extends TbQueueMsg, Response |
91 | 91 | List<Response> responses = responseTemplate.poll(pollInterval); |
92 | 92 | if (responses.size() > 0) { |
93 | 93 | log.trace("Polling responses completed, consumer records count [{}]", responses.size()); |
94 | - } else { | |
95 | - continue; | |
96 | 94 | } |
97 | 95 | responses.forEach(response -> { |
98 | 96 | byte[] requestIdHeader = response.getHeaders().get(REQUEST_ID_HEADER); | ... | ... |
... | ... | @@ -20,7 +20,7 @@ |
20 | 20 | <modelVersion>4.0.0</modelVersion> |
21 | 21 | <parent> |
22 | 22 | <groupId>org.thingsboard.common</groupId> |
23 | - <version>2.5.1-SNAPSHOT</version> | |
23 | + <version>2.5.3-SNAPSHOT</version> | |
24 | 24 | <artifactId>transport</artifactId> |
25 | 25 | </parent> |
26 | 26 | <groupId>org.thingsboard.common.transport</groupId> | ... | ... |
... | ... | @@ -20,7 +20,7 @@ |
20 | 20 | <modelVersion>4.0.0</modelVersion> |
21 | 21 | <parent> |
22 | 22 | <groupId>org.thingsboard.common</groupId> |
23 | - <version>2.5.1-SNAPSHOT</version> | |
23 | + <version>2.5.3-SNAPSHOT</version> | |
24 | 24 | <artifactId>transport</artifactId> |
25 | 25 | </parent> |
26 | 26 | <groupId>org.thingsboard.common.transport</groupId> | ... | ... |
... | ... | @@ -20,7 +20,7 @@ |
20 | 20 | <modelVersion>4.0.0</modelVersion> |
21 | 21 | <parent> |
22 | 22 | <groupId>org.thingsboard.common</groupId> |
23 | - <version>2.5.1-SNAPSHOT</version> | |
23 | + <version>2.5.3-SNAPSHOT</version> | |
24 | 24 | <artifactId>transport</artifactId> |
25 | 25 | </parent> |
26 | 26 | <groupId>org.thingsboard.common.transport</groupId> | ... | ... |
... | ... | @@ -521,11 +521,22 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement |
521 | 521 | .setDeviceName(msg.getDeviceInfo().getDeviceName()) |
522 | 522 | .setDeviceType(msg.getDeviceInfo().getDeviceType()) |
523 | 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 | 20 | <modelVersion>4.0.0</modelVersion> |
21 | 21 | <parent> |
22 | 22 | <groupId>org.thingsboard</groupId> |
23 | - <version>2.5.1-SNAPSHOT</version> | |
23 | + <version>2.5.3-SNAPSHOT</version> | |
24 | 24 | <artifactId>common</artifactId> |
25 | 25 | </parent> |
26 | 26 | <groupId>org.thingsboard.common</groupId> | ... | ... |
... | ... | @@ -20,7 +20,7 @@ |
20 | 20 | <modelVersion>4.0.0</modelVersion> |
21 | 21 | <parent> |
22 | 22 | <groupId>org.thingsboard.common</groupId> |
23 | - <version>2.5.1-SNAPSHOT</version> | |
23 | + <version>2.5.3-SNAPSHOT</version> | |
24 | 24 | <artifactId>transport</artifactId> |
25 | 25 | </parent> |
26 | 26 | <groupId>org.thingsboard.common.transport</groupId> | ... | ... |
... | ... | @@ -20,7 +20,7 @@ |
20 | 20 | <modelVersion>4.0.0</modelVersion> |
21 | 21 | <parent> |
22 | 22 | <groupId>org.thingsboard</groupId> |
23 | - <version>2.5.1-SNAPSHOT</version> | |
23 | + <version>2.5.3-SNAPSHOT</version> | |
24 | 24 | <artifactId>common</artifactId> |
25 | 25 | </parent> |
26 | 26 | <groupId>org.thingsboard.common</groupId> | ... | ... |
... | ... | @@ -20,7 +20,7 @@ |
20 | 20 | <modelVersion>4.0.0</modelVersion> |
21 | 21 | <parent> |
22 | 22 | <groupId>org.thingsboard</groupId> |
23 | - <version>2.5.1-SNAPSHOT</version> | |
23 | + <version>2.5.3-SNAPSHOT</version> | |
24 | 24 | <artifactId>thingsboard</artifactId> |
25 | 25 | </parent> |
26 | 26 | <artifactId>dao</artifactId> |
... | ... | @@ -91,26 +91,26 @@ |
91 | 91 | <artifactId>mockito-all</artifactId> |
92 | 92 | <scope>test</scope> |
93 | 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 | 106 | <dependency> |
107 | 107 | <groupId>org.springframework</groupId> |
108 | 108 | <artifactId>spring-context</artifactId> |
109 | 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 | 114 | <dependency> |
115 | 115 | <groupId>org.springframework</groupId> |
116 | 116 | <artifactId>spring-web</artifactId> |
... | ... | @@ -120,24 +120,24 @@ |
120 | 120 | <groupId>org.springframework.security</groupId> |
121 | 121 | <artifactId>spring-security-oauth2-client</artifactId> |
122 | 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 | 135 | <dependency> |
136 | 136 | <groupId>io.takari.junit</groupId> |
137 | 137 | <artifactId>takari-cpsuite</artifactId> |
138 | 138 | <scope>test</scope> |
139 | - </dependency> | |
140 | - <dependency> | |
139 | + </dependency> | |
140 | + <dependency> | |
141 | 141 | <groupId>com.google.guava</groupId> |
142 | 142 | <artifactId>guava</artifactId> |
143 | 143 | </dependency> |
... | ... | @@ -215,18 +215,18 @@ |
215 | 215 | </includes> |
216 | 216 | </configuration> |
217 | 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 | 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 | 230 | </plugins> |
231 | 231 | </build> |
232 | 232 | </project> | ... | ... |
... | ... | @@ -17,7 +17,6 @@ package org.thingsboard.server.dao.service; |
17 | 17 | |
18 | 18 | import com.fasterxml.jackson.databind.JsonNode; |
19 | 19 | import lombok.extern.slf4j.Slf4j; |
20 | -import org.apache.commons.validator.routines.EmailValidator; | |
21 | 20 | import org.thingsboard.server.common.data.BaseData; |
22 | 21 | import org.thingsboard.server.common.data.id.TenantId; |
23 | 22 | import org.thingsboard.server.dao.exception.DataValidationException; |
... | ... | @@ -26,11 +25,13 @@ import java.util.HashSet; |
26 | 25 | import java.util.Iterator; |
27 | 26 | import java.util.Set; |
28 | 27 | import java.util.function.Function; |
28 | +import java.util.regex.Matcher; | |
29 | +import java.util.regex.Pattern; | |
29 | 30 | |
30 | 31 | @Slf4j |
31 | 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 | 36 | public void validate(D data, Function<D, TenantId> tenantIdFunction) { |
36 | 37 | try { |
... | ... | @@ -64,11 +65,20 @@ public abstract class DataValidator<D extends BaseData<?>> { |
64 | 65 | } |
65 | 66 | |
66 | 67 | protected static void validateEmail(String email) { |
67 | - if (!emailValidator.isValid(email)) { | |
68 | + if (!doValidateEmail(email)) { | |
68 | 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 | 82 | protected static void validateJsonStructure(JsonNode expectedNode, JsonNode actualNode) { |
73 | 83 | Set<String> expectedFields = new HashSet<>(); |
74 | 84 | Iterator<String> fieldsIterator = expectedNode.fieldNames(); | ... | ... |
... | ... | @@ -4,15 +4,15 @@ This folder containing scripts and Kubernetes resources configurations to run Th |
4 | 4 | |
5 | 5 | ## Prerequisites |
6 | 6 | |
7 | -ThingsBoard Microservices are running on Kubernetes cluster. | |
7 | +ThingsBoard Microservices run on the Kubernetes cluster. | |
8 | 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 | 10 | or you can choose any other available [Kubernetes cluster deployment solutions](https://kubernetes.io/docs/setup/pick-right-solution/). |
11 | 11 | |
12 | 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 | 18 | $ minikube addons enable ingress |
... | ... | @@ -21,21 +21,21 @@ $ minikube addons enable ingress |
21 | 21 | ## Installation |
22 | 22 | |
23 | 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 | 26 | - `postgres` - use PostgreSQL database; |
27 | 27 | - `cassandra` - use Cassandra database; |
28 | 28 | |
29 | 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 | 41 | $ ./k8s-install-tb.sh --loadDemo |
... | ... | @@ -47,7 +47,7 @@ Where: |
47 | 47 | |
48 | 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 | 53 | $ ./k8s-deploy-thirdparty.sh |
... | ... | @@ -61,8 +61,8 @@ Execute the following command to deploy resources: |
61 | 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 | 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 | 73 | - **Tenant Administrator**: tenant@thingsboard.org / tenant |
74 | 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 | 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 | 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 | 88 | $ kubectl logs -f [tb-node-pod-name] |
... | ... | @@ -103,7 +103,7 @@ Execute the following command to delete all ThingsBoard microservices: |
103 | 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 | 109 | $ ./k8s-delete-thirdparty.sh | ... | ... |