66 changed files with 1014 additions and 758 deletions
@ -1,48 +0,0 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.actors.ruleChain; |
|||
|
|||
import lombok.Data; |
|||
import org.thingsboard.server.common.data.id.RuleChainId; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.msg.MsgType; |
|||
import org.thingsboard.server.common.msg.aware.RuleChainAwareMsg; |
|||
import org.thingsboard.server.common.msg.aware.TenantAwareMsg; |
|||
|
|||
import java.io.Serializable; |
|||
|
|||
/** |
|||
* Created by ashvayka on 19.03.18. |
|||
*/ |
|||
@Data |
|||
final class RemoteToRuleChainTellNextMsg extends RuleNodeToRuleChainTellNextMsg implements TenantAwareMsg, RuleChainAwareMsg { |
|||
|
|||
private static final long serialVersionUID = 2459605482321657447L; |
|||
private final TenantId tenantId; |
|||
private final RuleChainId ruleChainId; |
|||
|
|||
public RemoteToRuleChainTellNextMsg(RuleNodeToRuleChainTellNextMsg original, TenantId tenantId, RuleChainId ruleChainId) { |
|||
super(original.getOriginator(), original.getRelationTypes(), original.getMsg()); |
|||
this.tenantId = tenantId; |
|||
this.ruleChainId = ruleChainId; |
|||
} |
|||
|
|||
@Override |
|||
public MsgType getMsgType() { |
|||
return MsgType.REMOTE_TO_RULE_CHAIN_TELL_NEXT_MSG; |
|||
} |
|||
|
|||
} |
|||
@ -1,93 +0,0 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.actors.shared; |
|||
|
|||
import akka.actor.ActorContext; |
|||
import akka.actor.ActorRef; |
|||
import akka.actor.Props; |
|||
import akka.actor.UntypedActor; |
|||
import akka.japi.Creator; |
|||
import com.google.common.collect.BiMap; |
|||
import com.google.common.collect.HashBiMap; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.thingsboard.server.actors.ActorSystemContext; |
|||
import org.thingsboard.server.actors.ruleChain.RuleChainActor; |
|||
import org.thingsboard.server.actors.service.ContextAwareActor; |
|||
import org.thingsboard.server.common.data.SearchTextBased; |
|||
import org.thingsboard.server.common.data.id.EntityId; |
|||
import org.thingsboard.server.common.data.id.RuleChainId; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.data.id.UUIDBased; |
|||
import org.thingsboard.server.common.data.page.PageDataIterable; |
|||
|
|||
import java.util.HashMap; |
|||
import java.util.Map; |
|||
|
|||
/** |
|||
* Created by ashvayka on 15.03.18. |
|||
*/ |
|||
@Slf4j |
|||
public abstract class EntityActorsManager<T extends EntityId, A extends UntypedActor, M extends SearchTextBased<? extends UUIDBased>> { |
|||
|
|||
protected final ActorSystemContext systemContext; |
|||
protected final BiMap<T, ActorRef> actors; |
|||
|
|||
public EntityActorsManager(ActorSystemContext systemContext) { |
|||
this.systemContext = systemContext; |
|||
this.actors = HashBiMap.create(); |
|||
} |
|||
|
|||
protected abstract TenantId getTenantId(); |
|||
|
|||
protected abstract String getDispatcherName(); |
|||
|
|||
protected abstract Creator<A> creator(T entityId); |
|||
|
|||
protected abstract PageDataIterable.FetchFunction<M> getFetchEntitiesFunction(); |
|||
|
|||
public void init(ActorContext context) { |
|||
for (M entity : new PageDataIterable<>(getFetchEntitiesFunction(), ContextAwareActor.ENTITY_PACK_LIMIT)) { |
|||
T entityId = (T) entity.getId(); |
|||
log.debug("[{}|{}] Creating entity actor", entityId.getEntityType(), entityId.getId()); |
|||
//TODO: remove this cast making UUIDBased subclass of EntityId an interface and vice versa.
|
|||
ActorRef actorRef = getOrCreateActor(context, entityId); |
|||
visit(entity, actorRef); |
|||
log.debug("[{}|{}] Entity actor created.", entityId.getEntityType(), entityId.getId()); |
|||
} |
|||
} |
|||
|
|||
public void visit(M entity, ActorRef actorRef) { |
|||
} |
|||
|
|||
public ActorRef getOrCreateActor(ActorContext context, T entityId) { |
|||
return actors.computeIfAbsent(entityId, eId -> |
|||
context.actorOf(Props.create(creator(eId)) |
|||
.withDispatcher(getDispatcherName()), eId.toString())); |
|||
} |
|||
|
|||
public void broadcast(Object msg) { |
|||
actors.values().forEach(actorRef -> actorRef.tell(msg, ActorRef.noSender())); |
|||
} |
|||
|
|||
public void remove(T id) { |
|||
actors.remove(id); |
|||
} |
|||
|
|||
public ActorRef get(T id) { |
|||
return actors.get(id); |
|||
} |
|||
|
|||
} |
|||
@ -1,59 +0,0 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.actors.shared.rulechain; |
|||
|
|||
import akka.actor.ActorRef; |
|||
import akka.japi.Creator; |
|||
import lombok.Getter; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.thingsboard.server.actors.ActorSystemContext; |
|||
import org.thingsboard.server.actors.ruleChain.RuleChainActor; |
|||
import org.thingsboard.server.actors.shared.EntityActorsManager; |
|||
import org.thingsboard.server.common.data.id.RuleChainId; |
|||
import org.thingsboard.server.common.data.rule.RuleChain; |
|||
import org.thingsboard.server.dao.rule.RuleChainService; |
|||
|
|||
/** |
|||
* Created by ashvayka on 15.03.18. |
|||
*/ |
|||
@Slf4j |
|||
public abstract class RuleChainManager extends EntityActorsManager<RuleChainId, RuleChainActor, RuleChain> { |
|||
|
|||
protected final RuleChainService service; |
|||
@Getter |
|||
protected RuleChain rootChain; |
|||
@Getter |
|||
protected ActorRef rootChainActor; |
|||
|
|||
public RuleChainManager(ActorSystemContext systemContext) { |
|||
super(systemContext); |
|||
this.service = systemContext.getRuleChainService(); |
|||
} |
|||
|
|||
@Override |
|||
public Creator<RuleChainActor> creator(RuleChainId entityId) { |
|||
return new RuleChainActor.ActorCreator(systemContext, getTenantId(), entityId); |
|||
} |
|||
|
|||
@Override |
|||
public void visit(RuleChain entity, ActorRef actorRef) { |
|||
if (entity != null && entity.isRoot()) { |
|||
rootChain = entity; |
|||
rootChainActor = actorRef; |
|||
} |
|||
} |
|||
|
|||
} |
|||
@ -1,48 +0,0 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.actors.shared.rulechain; |
|||
|
|||
import org.thingsboard.server.actors.ActorSystemContext; |
|||
import org.thingsboard.server.actors.service.DefaultActorService; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.data.page.PageDataIterable.FetchFunction; |
|||
import org.thingsboard.server.common.data.page.TextPageData; |
|||
import org.thingsboard.server.common.data.rule.RuleChain; |
|||
import org.thingsboard.server.dao.model.ModelConstants; |
|||
|
|||
import java.util.Collections; |
|||
|
|||
public class SystemRuleChainManager extends RuleChainManager { |
|||
|
|||
public SystemRuleChainManager(ActorSystemContext systemContext) { |
|||
super(systemContext); |
|||
} |
|||
|
|||
@Override |
|||
protected FetchFunction<RuleChain> getFetchEntitiesFunction() { |
|||
return link -> new TextPageData<>(Collections.emptyList(), link); |
|||
} |
|||
|
|||
@Override |
|||
protected TenantId getTenantId() { |
|||
return ModelConstants.SYSTEM_TENANT; |
|||
} |
|||
|
|||
@Override |
|||
protected String getDispatcherName() { |
|||
return DefaultActorService.SYSTEM_RULE_DISPATCHER_NAME; |
|||
} |
|||
} |
|||
@ -1,53 +0,0 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.actors.shared.rulechain; |
|||
|
|||
import akka.actor.ActorContext; |
|||
import org.thingsboard.server.actors.ActorSystemContext; |
|||
import org.thingsboard.server.actors.service.DefaultActorService; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.data.page.PageDataIterable.FetchFunction; |
|||
import org.thingsboard.server.common.data.rule.RuleChain; |
|||
|
|||
public class TenantRuleChainManager extends RuleChainManager { |
|||
|
|||
private final TenantId tenantId; |
|||
|
|||
public TenantRuleChainManager(ActorSystemContext systemContext, TenantId tenantId) { |
|||
super(systemContext); |
|||
this.tenantId = tenantId; |
|||
} |
|||
|
|||
@Override |
|||
public void init(ActorContext context) { |
|||
super.init(context); |
|||
} |
|||
|
|||
@Override |
|||
protected TenantId getTenantId() { |
|||
return tenantId; |
|||
} |
|||
|
|||
@Override |
|||
protected String getDispatcherName() { |
|||
return DefaultActorService.TENANT_RULE_DISPATCHER_NAME; |
|||
} |
|||
|
|||
@Override |
|||
protected FetchFunction<RuleChain> getFetchEntitiesFunction() { |
|||
return link -> service.findTenantRuleChains(tenantId, link); |
|||
} |
|||
} |
|||
@ -0,0 +1,78 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.service.queue; |
|||
|
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.msg.queue.RuleEngineException; |
|||
import org.thingsboard.server.common.msg.queue.RuleNodeException; |
|||
import org.thingsboard.server.common.msg.queue.TbCallback; |
|||
import org.thingsboard.server.common.msg.queue.TbMsgCallback; |
|||
|
|||
import java.util.UUID; |
|||
import java.util.concurrent.ConcurrentMap; |
|||
import java.util.concurrent.CountDownLatch; |
|||
|
|||
@Slf4j |
|||
public class TbMsgPackCallback<T> implements TbMsgCallback { |
|||
private final CountDownLatch processingTimeoutLatch; |
|||
private final ConcurrentMap<UUID, T> ackMap; |
|||
private final ConcurrentMap<UUID, T> successMap; |
|||
private final ConcurrentMap<UUID, T> failedMap; |
|||
private final UUID id; |
|||
private final TenantId tenantId; |
|||
private final ConcurrentMap<TenantId, RuleEngineException> firstExceptions; |
|||
|
|||
public TbMsgPackCallback(UUID id, TenantId tenantId, |
|||
CountDownLatch processingTimeoutLatch, |
|||
ConcurrentMap<UUID, T> ackMap, |
|||
ConcurrentMap<UUID, T> successMap, |
|||
ConcurrentMap<UUID, T> failedMap, |
|||
ConcurrentMap<TenantId, RuleEngineException> firstExceptions) { |
|||
this.id = id; |
|||
this.tenantId = tenantId; |
|||
this.processingTimeoutLatch = processingTimeoutLatch; |
|||
this.ackMap = ackMap; |
|||
this.successMap = successMap; |
|||
this.failedMap = failedMap; |
|||
this.firstExceptions = firstExceptions; |
|||
} |
|||
|
|||
@Override |
|||
public void onSuccess() { |
|||
log.trace("[{}] ON SUCCESS", id); |
|||
T msg = ackMap.remove(id); |
|||
if (msg != null) { |
|||
successMap.put(id, msg); |
|||
} |
|||
if (msg != null && ackMap.isEmpty()) { |
|||
processingTimeoutLatch.countDown(); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public void onFailure(RuleEngineException e) { |
|||
log.trace("[{}] ON FAILURE", id, e); |
|||
T msg = ackMap.remove(id); |
|||
if (msg != null) { |
|||
failedMap.put(id, msg); |
|||
firstExceptions.putIfAbsent(tenantId, e); |
|||
} |
|||
if (ackMap.isEmpty()) { |
|||
processingTimeoutLatch.countDown(); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,92 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.service.queue; |
|||
|
|||
import lombok.Data; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
|
|||
import java.util.HashMap; |
|||
import java.util.Map; |
|||
import java.util.UUID; |
|||
import java.util.concurrent.atomic.AtomicInteger; |
|||
|
|||
@Slf4j |
|||
@Data |
|||
public class TbTenantRuleEngineStats { |
|||
|
|||
private final UUID tenantId; |
|||
|
|||
private final AtomicInteger totalMsgCounter = new AtomicInteger(0); |
|||
private final AtomicInteger successMsgCounter = new AtomicInteger(0); |
|||
private final AtomicInteger tmpTimeoutMsgCounter = new AtomicInteger(0); |
|||
private final AtomicInteger tmpFailedMsgCounter = new AtomicInteger(0); |
|||
|
|||
private final AtomicInteger timeoutMsgCounter = new AtomicInteger(0); |
|||
private final AtomicInteger failedMsgCounter = new AtomicInteger(0); |
|||
|
|||
private final Map<String, AtomicInteger> counters = new HashMap<>(); |
|||
|
|||
public TbTenantRuleEngineStats(UUID tenantId) { |
|||
this.tenantId = tenantId; |
|||
counters.put(TbRuleEngineConsumerStats.TOTAL_MSGS, totalMsgCounter); |
|||
counters.put(TbRuleEngineConsumerStats.SUCCESSFUL_MSGS, successMsgCounter); |
|||
counters.put(TbRuleEngineConsumerStats.TIMEOUT_MSGS, timeoutMsgCounter); |
|||
counters.put(TbRuleEngineConsumerStats.FAILED_MSGS, failedMsgCounter); |
|||
|
|||
counters.put(TbRuleEngineConsumerStats.TMP_TIMEOUT, tmpTimeoutMsgCounter); |
|||
counters.put(TbRuleEngineConsumerStats.TMP_FAILED, tmpFailedMsgCounter); |
|||
} |
|||
|
|||
public void logSuccess() { |
|||
totalMsgCounter.incrementAndGet(); |
|||
successMsgCounter.incrementAndGet(); |
|||
} |
|||
|
|||
public void logFailed() { |
|||
totalMsgCounter.incrementAndGet(); |
|||
failedMsgCounter.incrementAndGet(); |
|||
} |
|||
|
|||
public void logTimeout() { |
|||
totalMsgCounter.incrementAndGet(); |
|||
timeoutMsgCounter.incrementAndGet(); |
|||
} |
|||
|
|||
public void logTmpFailed() { |
|||
totalMsgCounter.incrementAndGet(); |
|||
tmpFailedMsgCounter.incrementAndGet(); |
|||
} |
|||
|
|||
public void logTmpTimeout() { |
|||
totalMsgCounter.incrementAndGet(); |
|||
tmpTimeoutMsgCounter.incrementAndGet(); |
|||
} |
|||
|
|||
public void printStats() { |
|||
int total = totalMsgCounter.get(); |
|||
if (total > 0) { |
|||
StringBuilder stats = new StringBuilder(); |
|||
counters.forEach((label, value) -> { |
|||
stats.append(label).append(" = [").append(value.get()).append("]"); |
|||
}); |
|||
log.info("[{}] Stats: {}", tenantId, stats); |
|||
} |
|||
} |
|||
|
|||
public void reset() { |
|||
counters.values().forEach(counter -> counter.set(0)); |
|||
} |
|||
} |
|||
@ -0,0 +1,127 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.service.stats; |
|||
|
|||
import com.google.common.util.concurrent.FutureCallback; |
|||
import lombok.Data; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.stereotype.Service; |
|||
import org.thingsboard.server.common.data.asset.Asset; |
|||
import org.thingsboard.server.common.data.id.AssetId; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.data.kv.BasicTsKvEntry; |
|||
import org.thingsboard.server.common.data.kv.JsonDataEntry; |
|||
import org.thingsboard.server.common.data.kv.LongDataEntry; |
|||
import org.thingsboard.server.common.data.kv.TsKvEntry; |
|||
import org.thingsboard.server.dao.asset.AssetService; |
|||
import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; |
|||
import org.thingsboard.server.queue.util.TbRuleEngineComponent; |
|||
import org.thingsboard.server.service.queue.TbRuleEngineConsumerStats; |
|||
import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService; |
|||
|
|||
import javax.annotation.Nullable; |
|||
import java.util.Collections; |
|||
import java.util.List; |
|||
import java.util.concurrent.ConcurrentHashMap; |
|||
import java.util.concurrent.ConcurrentMap; |
|||
import java.util.concurrent.locks.Lock; |
|||
import java.util.concurrent.locks.ReentrantLock; |
|||
import java.util.stream.Collectors; |
|||
|
|||
@TbRuleEngineComponent |
|||
@Service |
|||
@Slf4j |
|||
public class DefaultRuleEngineStatisticsService implements RuleEngineStatisticsService { |
|||
|
|||
public static final FutureCallback<Void> CALLBACK = new FutureCallback<Void>() { |
|||
@Override |
|||
public void onSuccess(@Nullable Void result) { |
|||
|
|||
} |
|||
|
|||
@Override |
|||
public void onFailure(Throwable t) { |
|||
log.warn("Failed to persist statistics", t); |
|||
} |
|||
}; |
|||
|
|||
private final TbServiceInfoProvider serviceInfoProvider; |
|||
private final TelemetrySubscriptionService tsService; |
|||
private final Lock lock = new ReentrantLock(); |
|||
private final AssetService assetService; |
|||
private final ConcurrentMap<TenantQueueKey, AssetId> tenantQueueAssets; |
|||
|
|||
public DefaultRuleEngineStatisticsService(TelemetrySubscriptionService tsService, TbServiceInfoProvider serviceInfoProvider, AssetService assetService) { |
|||
this.tsService = tsService; |
|||
this.serviceInfoProvider = serviceInfoProvider; |
|||
this.assetService = assetService; |
|||
this.tenantQueueAssets = new ConcurrentHashMap<>(); |
|||
} |
|||
|
|||
@Override |
|||
public void reportQueueStats(long ts, TbRuleEngineConsumerStats ruleEngineStats) { |
|||
String queueName = ruleEngineStats.getQueueName(); |
|||
ruleEngineStats.getTenantStats().forEach((id, stats) -> { |
|||
TenantId tenantId = new TenantId(id); |
|||
AssetId serviceAssetId = getServiceAssetId(tenantId, queueName); |
|||
if (stats.getTotalMsgCounter().get() > 0) { |
|||
List<TsKvEntry> tsList = stats.getCounters().entrySet().stream() |
|||
.map(kv -> new BasicTsKvEntry(ts, new LongDataEntry(kv.getKey(), (long) kv.getValue().get()))) |
|||
.collect(Collectors.toList()); |
|||
if (!tsList.isEmpty()) { |
|||
tsService.saveAndNotify(tenantId, serviceAssetId, tsList, CALLBACK); |
|||
} |
|||
} |
|||
}); |
|||
ruleEngineStats.getTenantExceptions().forEach((tenantId, e) -> { |
|||
TsKvEntry tsKv = new BasicTsKvEntry(ts, new JsonDataEntry("ruleEngineException", e.toJsonString())); |
|||
tsService.saveAndNotify(tenantId, getServiceAssetId(tenantId, queueName), Collections.singletonList(tsKv), CALLBACK); |
|||
}); |
|||
ruleEngineStats.reset(); |
|||
} |
|||
|
|||
private AssetId getServiceAssetId(TenantId tenantId, String queueName) { |
|||
TenantQueueKey key = new TenantQueueKey(tenantId, queueName); |
|||
AssetId assetId = tenantQueueAssets.get(key); |
|||
if (assetId == null) { |
|||
lock.lock(); |
|||
try { |
|||
assetId = tenantQueueAssets.get(key); |
|||
if (assetId == null) { |
|||
Asset asset = assetService.findAssetByTenantIdAndName(tenantId, queueName + "_" + serviceInfoProvider.getServiceId()); |
|||
if (asset == null) { |
|||
asset = new Asset(); |
|||
asset.setTenantId(tenantId); |
|||
asset.setName(queueName + "_" + serviceInfoProvider.getServiceId()); |
|||
asset.setType("TbServiceQueue"); |
|||
asset = assetService.saveAsset(asset); |
|||
} |
|||
assetId = asset.getId(); |
|||
tenantQueueAssets.put(key, assetId); |
|||
} |
|||
} finally { |
|||
lock.unlock(); |
|||
} |
|||
} |
|||
return assetId; |
|||
} |
|||
|
|||
@Data |
|||
private static class TenantQueueKey { |
|||
private final TenantId tenantId; |
|||
private final String queueName; |
|||
} |
|||
} |
|||
@ -1,80 +0,0 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.service.telemetry.sub; |
|||
|
|||
import lombok.AllArgsConstructor; |
|||
import lombok.Data; |
|||
import org.thingsboard.server.common.data.id.EntityId; |
|||
import org.thingsboard.server.common.msg.cluster.ServerAddress; |
|||
import org.thingsboard.server.service.telemetry.TelemetryFeature; |
|||
|
|||
import java.util.Map; |
|||
|
|||
@Data |
|||
@AllArgsConstructor |
|||
public class Subscription { |
|||
|
|||
private final SubscriptionState sub; |
|||
private final boolean local; |
|||
private ServerAddress server; |
|||
private long startTime; |
|||
private long endTime; |
|||
|
|||
public Subscription(SubscriptionState sub, boolean local, ServerAddress server) { |
|||
this(sub, local, server, 0L, 0L); |
|||
} |
|||
|
|||
public String getWsSessionId() { |
|||
return getSub().getWsSessionId(); |
|||
} |
|||
|
|||
public int getSubscriptionId() { |
|||
return getSub().getSubscriptionId(); |
|||
} |
|||
|
|||
public EntityId getEntityId() { |
|||
return getSub().getEntityId(); |
|||
} |
|||
|
|||
public TelemetryFeature getType() { |
|||
return getSub().getType(); |
|||
} |
|||
|
|||
public String getScope() { |
|||
return getSub().getScope(); |
|||
} |
|||
|
|||
public boolean isAllKeys() { |
|||
return getSub().isAllKeys(); |
|||
} |
|||
|
|||
public Map<String, Long> getKeyStates() { |
|||
return getSub().getKeyStates(); |
|||
} |
|||
|
|||
public void setKeyState(String key, long ts) { |
|||
getSub().getKeyStates().put(key, ts); |
|||
} |
|||
|
|||
@Override |
|||
public String toString() { |
|||
return "Subscription{" + |
|||
"sub=" + sub + |
|||
", local=" + local + |
|||
", server=" + server + |
|||
'}'; |
|||
} |
|||
} |
|||
@ -1,47 +0,0 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.common.msg.cluster; |
|||
|
|||
import lombok.Data; |
|||
import lombok.EqualsAndHashCode; |
|||
|
|||
import java.io.Serializable; |
|||
|
|||
/** |
|||
* @author Andrew Shvayka |
|||
*/ |
|||
@Data |
|||
@EqualsAndHashCode |
|||
public class ServerAddress implements Comparable<ServerAddress>, Serializable { |
|||
|
|||
private final String host; |
|||
private final int port; |
|||
private final ServerType serverType; |
|||
|
|||
@Override |
|||
public int compareTo(ServerAddress o) { |
|||
int result = this.host.compareTo(o.host); |
|||
if (result == 0) { |
|||
result = this.port - o.port; |
|||
} |
|||
return result; |
|||
} |
|||
|
|||
@Override |
|||
public String toString() { |
|||
return '[' + host + ':' + port + ']'; |
|||
} |
|||
} |
|||
@ -0,0 +1,38 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.common.msg.queue; |
|||
|
|||
import com.fasterxml.jackson.core.JsonProcessingException; |
|||
import com.fasterxml.jackson.databind.ObjectMapper; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
|
|||
@Slf4j |
|||
public class RuleEngineException extends Exception { |
|||
protected static final ObjectMapper mapper = new ObjectMapper(); |
|||
|
|||
public RuleEngineException(String message) { |
|||
super(message != null ? message : "Unknown"); |
|||
} |
|||
|
|||
public String toJsonString() { |
|||
try { |
|||
return mapper.writeValueAsString(mapper.createObjectNode().put("message", getMessage())); |
|||
} catch (JsonProcessingException e) { |
|||
log.warn("Failed to serialize exception ", e); |
|||
throw new RuntimeException(e); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,58 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.common.msg.queue; |
|||
|
|||
import com.fasterxml.jackson.core.JsonProcessingException; |
|||
import lombok.Getter; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.thingsboard.server.common.data.id.RuleChainId; |
|||
import org.thingsboard.server.common.data.id.RuleNodeId; |
|||
import org.thingsboard.server.common.data.rule.RuleNode; |
|||
|
|||
@Slf4j |
|||
public class RuleNodeException extends RuleEngineException { |
|||
@Getter |
|||
private final String ruleChainName; |
|||
@Getter |
|||
private final String ruleNodeName; |
|||
@Getter |
|||
private final RuleChainId ruleChainId; |
|||
@Getter |
|||
private final RuleNodeId ruleNodeId; |
|||
|
|||
public RuleNodeException(String message, String ruleChainName, RuleNode ruleNode) { |
|||
super(message); |
|||
this.ruleChainName = ruleChainName; |
|||
this.ruleNodeName = ruleNode.getName(); |
|||
this.ruleChainId = ruleNode.getRuleChainId(); |
|||
this.ruleNodeId = ruleNode.getId(); |
|||
} |
|||
|
|||
public String toJsonString() { |
|||
try { |
|||
return mapper.writeValueAsString(mapper.createObjectNode() |
|||
.put("ruleNodeId", ruleNodeId.toString()) |
|||
.put("ruleChainId", ruleChainId.toString()) |
|||
.put("ruleNodeName", ruleNodeName) |
|||
.put("ruleChainName", ruleChainName) |
|||
.put("message", getMessage())); |
|||
} catch (JsonProcessingException e) { |
|||
log.warn("Failed to serialize exception ", e); |
|||
throw new RuntimeException(e); |
|||
} |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,37 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.common.msg.queue; |
|||
|
|||
public interface TbCallback { |
|||
|
|||
TbCallback EMPTY = new TbCallback() { |
|||
|
|||
@Override |
|||
public void onSuccess() { |
|||
|
|||
} |
|||
|
|||
@Override |
|||
public void onFailure(Throwable t) { |
|||
|
|||
} |
|||
}; |
|||
|
|||
void onSuccess(); |
|||
|
|||
void onFailure(Throwable t); |
|||
|
|||
} |
|||
@ -0,0 +1,53 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.rule.engine.flow; |
|||
|
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.thingsboard.rule.engine.api.EmptyNodeConfiguration; |
|||
import org.thingsboard.rule.engine.api.RuleNode; |
|||
import org.thingsboard.rule.engine.api.TbContext; |
|||
import org.thingsboard.rule.engine.api.TbNode; |
|||
import org.thingsboard.rule.engine.api.TbNodeConfiguration; |
|||
import org.thingsboard.rule.engine.api.TbNodeException; |
|||
import org.thingsboard.rule.engine.api.TbRelationTypes; |
|||
import org.thingsboard.rule.engine.api.util.TbNodeUtils; |
|||
import org.thingsboard.server.common.data.plugin.ComponentType; |
|||
import org.thingsboard.server.common.msg.TbMsg; |
|||
|
|||
@Slf4j |
|||
@RuleNode( |
|||
type = ComponentType.ACTION, |
|||
name = "acknowledge", |
|||
configClazz = EmptyNodeConfiguration.class, |
|||
nodeDescription = "Acknowledges the incoming message", |
|||
nodeDetails = "After acknowledgement, the message is pushed to related rule nodes. Useful if you don't care what happens to this message next.") |
|||
|
|||
public class TbAckNode implements TbNode { |
|||
|
|||
@Override |
|||
public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException { |
|||
} |
|||
|
|||
@Override |
|||
public void onMsg(TbContext ctx, TbMsg msg) { |
|||
ctx.ack(msg); |
|||
ctx.tellSuccess(msg); |
|||
} |
|||
|
|||
@Override |
|||
public void destroy() { |
|||
} |
|||
} |
|||
@ -0,0 +1,57 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.rule.engine.flow; |
|||
|
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.thingsboard.rule.engine.api.RuleNode; |
|||
import org.thingsboard.rule.engine.api.ScriptEngine; |
|||
import org.thingsboard.rule.engine.api.TbContext; |
|||
import org.thingsboard.rule.engine.api.TbNode; |
|||
import org.thingsboard.rule.engine.api.TbNodeConfiguration; |
|||
import org.thingsboard.rule.engine.api.TbNodeException; |
|||
import org.thingsboard.rule.engine.api.TbRelationTypes; |
|||
import org.thingsboard.rule.engine.api.util.TbNodeUtils; |
|||
import org.thingsboard.server.common.data.plugin.ComponentType; |
|||
import org.thingsboard.server.common.msg.TbMsg; |
|||
|
|||
import static org.thingsboard.common.util.DonAsynchron.withCallback; |
|||
|
|||
@Slf4j |
|||
@RuleNode( |
|||
type = ComponentType.ACTION, |
|||
name = "checkpoint", |
|||
configClazz = TbCheckpointNodeConfiguration.class, |
|||
nodeDescription = "transfers the message to another queue", |
|||
nodeDetails = "After successful transfer incoming message is automatically acknowledged. Queue name is configurable.") |
|||
|
|||
public class TbCheckpointNode implements TbNode { |
|||
|
|||
private TbCheckpointNodeConfiguration config; |
|||
|
|||
@Override |
|||
public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException { |
|||
this.config = TbNodeUtils.convert(configuration, TbCheckpointNodeConfiguration.class); |
|||
} |
|||
|
|||
@Override |
|||
public void onMsg(TbContext ctx, TbMsg msg) { |
|||
ctx.enqueueForTellNext(msg, config.getQueueName(), TbRelationTypes.SUCCESS, () -> ctx.ack(msg), error -> ctx.tellFailure(msg, error)); |
|||
} |
|||
|
|||
@Override |
|||
public void destroy() { |
|||
} |
|||
} |
|||
Loading…
Reference in new issue