15 changed files with 229 additions and 429 deletions
@ -1,161 +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.cluster.rpc; |
|
||||
|
|
||||
import com.google.protobuf.ByteString; |
|
||||
import io.grpc.Server; |
|
||||
import io.grpc.ServerBuilder; |
|
||||
import io.grpc.stub.StreamObserver; |
|
||||
import lombok.extern.slf4j.Slf4j; |
|
||||
import org.springframework.beans.factory.annotation.Autowired; |
|
||||
import org.springframework.stereotype.Service; |
|
||||
import org.thingsboard.server.actors.rpc.RpcBroadcastMsg; |
|
||||
import org.thingsboard.server.actors.rpc.RpcSessionCreateRequestMsg; |
|
||||
import org.thingsboard.server.common.msg.TbActorMsg; |
|
||||
import org.thingsboard.server.common.msg.cluster.ServerAddress; |
|
||||
import org.thingsboard.server.gen.cluster.ClusterAPIProtos; |
|
||||
import org.thingsboard.server.gen.cluster.ClusterRpcServiceGrpc; |
|
||||
import org.thingsboard.server.service.cluster.discovery.ServerInstance; |
|
||||
import org.thingsboard.server.service.cluster.discovery.ServerInstanceService; |
|
||||
import org.thingsboard.server.service.encoding.DataDecodingEncodingService; |
|
||||
|
|
||||
import javax.annotation.PreDestroy; |
|
||||
import java.io.IOException; |
|
||||
import java.util.UUID; |
|
||||
import java.util.concurrent.ArrayBlockingQueue; |
|
||||
import java.util.concurrent.BlockingQueue; |
|
||||
import java.util.concurrent.ConcurrentHashMap; |
|
||||
import java.util.concurrent.ConcurrentMap; |
|
||||
|
|
||||
/** |
|
||||
* @author Andrew Shvayka |
|
||||
*/ |
|
||||
@Service |
|
||||
@Slf4j |
|
||||
public class ClusterGrpcService extends ClusterRpcServiceGrpc.ClusterRpcServiceImplBase implements ClusterRpcService { |
|
||||
|
|
||||
@Autowired |
|
||||
private ServerInstanceService instanceService; |
|
||||
|
|
||||
@Autowired |
|
||||
private DataDecodingEncodingService encodingService; |
|
||||
|
|
||||
private RpcMsgListener listener; |
|
||||
|
|
||||
private Server server; |
|
||||
|
|
||||
private ServerInstance instance; |
|
||||
|
|
||||
private ConcurrentMap<UUID, BlockingQueue<StreamObserver<ClusterAPIProtos.ClusterMessage>>> pendingSessionMap = |
|
||||
new ConcurrentHashMap<>(); |
|
||||
|
|
||||
public void init(RpcMsgListener listener) { |
|
||||
this.listener = listener; |
|
||||
log.info("Initializing RPC service!"); |
|
||||
instance = instanceService.getSelf(); |
|
||||
server = ServerBuilder.forPort(instance.getPort()).addService(this).build(); |
|
||||
log.info("Going to start RPC server using port: {}", instance.getPort()); |
|
||||
try { |
|
||||
server.start(); |
|
||||
} catch (IOException e) { |
|
||||
log.error("Failed to start RPC server!", e); |
|
||||
throw new RuntimeException("Failed to start RPC server!"); |
|
||||
} |
|
||||
log.info("RPC service initialized!"); |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public void onSessionCreated(UUID msgUid, StreamObserver<ClusterAPIProtos.ClusterMessage> inputStream) { |
|
||||
BlockingQueue<StreamObserver<ClusterAPIProtos.ClusterMessage>> queue = pendingSessionMap.remove(msgUid); |
|
||||
if (queue != null) { |
|
||||
try { |
|
||||
queue.put(inputStream); |
|
||||
} catch (InterruptedException e) { |
|
||||
log.warn("Failed to report created session!"); |
|
||||
Thread.currentThread().interrupt(); |
|
||||
} |
|
||||
} else { |
|
||||
log.warn("Failed to lookup pending session!"); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public StreamObserver<ClusterAPIProtos.ClusterMessage> handleMsgs( |
|
||||
StreamObserver<ClusterAPIProtos.ClusterMessage> responseObserver) { |
|
||||
log.info("Processing new session."); |
|
||||
return createSession(new RpcSessionCreateRequestMsg(UUID.randomUUID(), null, responseObserver)); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
@PreDestroy |
|
||||
public void stop() { |
|
||||
if (server != null) { |
|
||||
log.info("Going to onStop RPC server"); |
|
||||
server.shutdownNow(); |
|
||||
try { |
|
||||
server.awaitTermination(); |
|
||||
log.info("RPC server stopped!"); |
|
||||
} catch (InterruptedException e) { |
|
||||
log.warn("Failed to onStop RPC server!"); |
|
||||
Thread.currentThread().interrupt(); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
|
|
||||
@Override |
|
||||
public void broadcast(RpcBroadcastMsg msg) { |
|
||||
listener.onBroadcastMsg(msg); |
|
||||
} |
|
||||
|
|
||||
private StreamObserver<ClusterAPIProtos.ClusterMessage> createSession(RpcSessionCreateRequestMsg msg) { |
|
||||
BlockingQueue<StreamObserver<ClusterAPIProtos.ClusterMessage>> queue = new ArrayBlockingQueue<>(1); |
|
||||
pendingSessionMap.put(msg.getMsgUid(), queue); |
|
||||
listener.onRpcSessionCreateRequestMsg(msg); |
|
||||
try { |
|
||||
StreamObserver<ClusterAPIProtos.ClusterMessage> observer = queue.take(); |
|
||||
log.info("Processed new session."); |
|
||||
return observer; |
|
||||
} catch (Exception e) { |
|
||||
log.info("Failed to process session.", e); |
|
||||
throw new RuntimeException(e); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public void tell(ClusterAPIProtos.ClusterMessage message) { |
|
||||
listener.onSendMsg(message); |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public void tell(ServerAddress serverAddress, TbActorMsg actorMsg) { |
|
||||
listener.onSendMsg(encodingService.convertToProtoDataMessage(serverAddress, actorMsg)); |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public void tell(ServerAddress serverAddress, ClusterAPIProtos.MessageType msgType, byte[] data) { |
|
||||
ClusterAPIProtos.ClusterMessage msg = ClusterAPIProtos.ClusterMessage |
|
||||
.newBuilder() |
|
||||
.setServerAddress(ClusterAPIProtos.ServerAddress |
|
||||
.newBuilder() |
|
||||
.setHost(serverAddress.getHost()) |
|
||||
.setPort(serverAddress.getPort()) |
|
||||
.build()) |
|
||||
.setMessageType(msgType) |
|
||||
.setPayload(ByteString.copyFrom(data)).build(); |
|
||||
listener.onSendMsg(msg); |
|
||||
} |
|
||||
} |
|
||||
@ -1,42 +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.cluster.rpc; |
|
||||
|
|
||||
import io.grpc.stub.StreamObserver; |
|
||||
import org.thingsboard.server.actors.rpc.RpcBroadcastMsg; |
|
||||
import org.thingsboard.server.common.msg.TbActorMsg; |
|
||||
import org.thingsboard.server.common.msg.cluster.ServerAddress; |
|
||||
import org.thingsboard.server.gen.cluster.ClusterAPIProtos; |
|
||||
|
|
||||
import java.util.UUID; |
|
||||
|
|
||||
/** |
|
||||
* @author Andrew Shvayka |
|
||||
*/ |
|
||||
public interface ClusterRpcService { |
|
||||
|
|
||||
void init(RpcMsgListener listener); |
|
||||
|
|
||||
void broadcast(RpcBroadcastMsg msg); |
|
||||
|
|
||||
void onSessionCreated(UUID msgUid, StreamObserver<ClusterAPIProtos.ClusterMessage> inputStream); |
|
||||
|
|
||||
void tell(ClusterAPIProtos.ClusterMessage message); |
|
||||
|
|
||||
void tell(ServerAddress serverAddress, TbActorMsg actorMsg); |
|
||||
|
|
||||
void tell(ServerAddress serverAddress, ClusterAPIProtos.MessageType msgType, byte[] data); |
|
||||
} |
|
||||
@ -1,125 +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.cluster.rpc; |
|
||||
|
|
||||
import io.grpc.Channel; |
|
||||
import io.grpc.ManagedChannel; |
|
||||
import io.grpc.stub.StreamObserver; |
|
||||
import lombok.Data; |
|
||||
import lombok.extern.slf4j.Slf4j; |
|
||||
import org.thingsboard.server.common.msg.cluster.ServerAddress; |
|
||||
import org.thingsboard.server.common.msg.cluster.ServerType; |
|
||||
import org.thingsboard.server.gen.cluster.ClusterAPIProtos; |
|
||||
|
|
||||
import java.io.Closeable; |
|
||||
import java.util.UUID; |
|
||||
|
|
||||
/** |
|
||||
* @author Andrew Shvayka |
|
||||
*/ |
|
||||
@Data |
|
||||
@Slf4j |
|
||||
public final class GrpcSession implements Closeable { |
|
||||
private final UUID sessionId; |
|
||||
private final boolean client; |
|
||||
private final GrpcSessionListener listener; |
|
||||
private final ManagedChannel channel; |
|
||||
private StreamObserver<ClusterAPIProtos.ClusterMessage> inputStream; |
|
||||
private StreamObserver<ClusterAPIProtos.ClusterMessage> outputStream; |
|
||||
|
|
||||
private boolean connected; |
|
||||
private ServerAddress remoteServer; |
|
||||
|
|
||||
public GrpcSession(GrpcSessionListener listener) { |
|
||||
this(null, listener, null); |
|
||||
} |
|
||||
|
|
||||
public GrpcSession(ServerAddress remoteServer, GrpcSessionListener listener, ManagedChannel channel) { |
|
||||
this.sessionId = UUID.randomUUID(); |
|
||||
this.listener = listener; |
|
||||
if (remoteServer != null) { |
|
||||
this.client = true; |
|
||||
this.connected = true; |
|
||||
this.remoteServer = remoteServer; |
|
||||
} else { |
|
||||
this.client = false; |
|
||||
} |
|
||||
this.channel = channel; |
|
||||
} |
|
||||
|
|
||||
public void initInputStream() { |
|
||||
this.inputStream = new StreamObserver<ClusterAPIProtos.ClusterMessage>() { |
|
||||
@Override |
|
||||
public void onNext(ClusterAPIProtos.ClusterMessage clusterMessage) { |
|
||||
if (!connected && clusterMessage.getMessageType() == ClusterAPIProtos.MessageType.CONNECT_RPC_MESSAGE) { |
|
||||
connected = true; |
|
||||
ServerAddress rpcAddress = new ServerAddress(clusterMessage.getServerAddress().getHost(), clusterMessage.getServerAddress().getPort(), ServerType.CORE); |
|
||||
remoteServer = new ServerAddress(rpcAddress.getHost(), rpcAddress.getPort(), ServerType.CORE); |
|
||||
listener.onConnected(GrpcSession.this); |
|
||||
} |
|
||||
if (connected) { |
|
||||
listener.onReceiveClusterGrpcMsg(GrpcSession.this, clusterMessage); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public void onError(Throwable t) { |
|
||||
listener.onError(GrpcSession.this, t); |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public void onCompleted() { |
|
||||
outputStream.onCompleted(); |
|
||||
listener.onDisconnected(GrpcSession.this); |
|
||||
} |
|
||||
}; |
|
||||
} |
|
||||
|
|
||||
public void initOutputStream() { |
|
||||
if (client) { |
|
||||
listener.onConnected(GrpcSession.this); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
public void sendMsg(ClusterAPIProtos.ClusterMessage msg) { |
|
||||
if (connected) { |
|
||||
try { |
|
||||
outputStream.onNext(msg); |
|
||||
} catch (Throwable t) { |
|
||||
try { |
|
||||
outputStream.onError(t); |
|
||||
} catch (Throwable t2) { |
|
||||
} |
|
||||
listener.onError(GrpcSession.this, t); |
|
||||
} |
|
||||
} else { |
|
||||
log.warn("[{}] Failed to send message due to closed session!", sessionId); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public void close() { |
|
||||
connected = false; |
|
||||
try { |
|
||||
outputStream.onCompleted(); |
|
||||
} catch (IllegalStateException e) { |
|
||||
log.debug("[{}] Failed to close output stream: {}", sessionId, e.getMessage()); |
|
||||
} |
|
||||
if (channel != null) { |
|
||||
channel.shutdownNow(); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,32 +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.cluster.rpc; |
|
||||
|
|
||||
import org.thingsboard.server.gen.cluster.ClusterAPIProtos; |
|
||||
|
|
||||
/** |
|
||||
* @author Andrew Shvayka |
|
||||
*/ |
|
||||
public interface GrpcSessionListener { |
|
||||
|
|
||||
void onConnected(GrpcSession session); |
|
||||
|
|
||||
void onDisconnected(GrpcSession session); |
|
||||
|
|
||||
void onReceiveClusterGrpcMsg(GrpcSession session, ClusterAPIProtos.ClusterMessage clusterMessage); |
|
||||
|
|
||||
void onError(GrpcSession session, Throwable t); |
|
||||
} |
|
||||
@ -1,32 +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.cluster.rpc; |
|
||||
|
|
||||
import org.thingsboard.server.actors.rpc.RpcBroadcastMsg; |
|
||||
import org.thingsboard.server.actors.rpc.RpcSessionCreateRequestMsg; |
|
||||
import org.thingsboard.server.common.msg.cluster.ServerAddress; |
|
||||
import org.thingsboard.server.gen.cluster.ClusterAPIProtos; |
|
||||
|
|
||||
/** |
|
||||
* @author Andrew Shvayka |
|
||||
*/ |
|
||||
|
|
||||
public interface RpcMsgListener { |
|
||||
void onReceivedMsg(ServerAddress remoteServer, ClusterAPIProtos.ClusterMessage msg); |
|
||||
void onSendMsg(ClusterAPIProtos.ClusterMessage msg); |
|
||||
void onRpcSessionCreateRequestMsg(RpcSessionCreateRequestMsg msg); |
|
||||
void onBroadcastMsg(RpcBroadcastMsg msg); |
|
||||
} |
|
||||
@ -0,0 +1,124 @@ |
|||||
|
package org.thingsboard.server.service.queue; |
||||
|
|
||||
|
import akka.actor.ActorRef; |
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.springframework.beans.factory.annotation.Value; |
||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; |
||||
|
import org.springframework.boot.context.event.ApplicationReadyEvent; |
||||
|
import org.springframework.context.event.EventListener; |
||||
|
import org.springframework.scheduling.annotation.Scheduled; |
||||
|
import org.springframework.stereotype.Service; |
||||
|
import org.thingsboard.common.util.ThingsBoardThreadFactory; |
||||
|
import org.thingsboard.server.TbQueueConsumer; |
||||
|
import org.thingsboard.server.actors.ActorSystemContext; |
||||
|
import org.thingsboard.server.common.TbProtoQueueMsg; |
||||
|
import org.thingsboard.server.gen.transport.TransportProtos; |
||||
|
import org.thingsboard.server.provider.TbCoreQueueProvider; |
||||
|
import org.thingsboard.server.service.transport.msg.TransportToDeviceActorMsgWrapper; |
||||
|
|
||||
|
import javax.annotation.PostConstruct; |
||||
|
import javax.annotation.PreDestroy; |
||||
|
import java.util.List; |
||||
|
import java.util.UUID; |
||||
|
import java.util.concurrent.ConcurrentMap; |
||||
|
import java.util.concurrent.CountDownLatch; |
||||
|
import java.util.concurrent.ExecutorService; |
||||
|
import java.util.concurrent.Executors; |
||||
|
import java.util.concurrent.TimeUnit; |
||||
|
import java.util.function.Function; |
||||
|
import java.util.stream.Collectors; |
||||
|
|
||||
|
@Service |
||||
|
@ConditionalOnExpression("'${service.type:null}'=='monolith' || '${service.type:null}'=='tb-rule-engine')") |
||||
|
@Slf4j |
||||
|
public class DefaultTbRuleEngineConsumerService implements TbRuleEngineConsumerService { |
||||
|
|
||||
|
|
||||
|
@Value("${queue.rule-engine.poll_interval}") |
||||
|
private long pollDuration; |
||||
|
@Value("${queue.rule-engine.pack_processing_timeout}") |
||||
|
private long packProcessingTimeout; |
||||
|
@Value("${queue.rule-engine.stats.enabled:false}") |
||||
|
private boolean statsEnabled; |
||||
|
|
||||
|
private final ActorSystemContext actorContext; |
||||
|
private final TbQueueConsumer<TbProtoQueueMsg<TransportProtos.ToCoreMsg>> consumer; |
||||
|
private final TbCoreConsumerStats stats = new TbCoreConsumerStats(); |
||||
|
private volatile ExecutorService mainConsumerExecutor; |
||||
|
private volatile boolean stopped = false; |
||||
|
|
||||
|
public DefaultTbRuleEngineConsumerService(TbCoreQueueProvider tbCoreQueueProvider, ActorSystemContext actorContext) { |
||||
|
this.consumer = tbCoreQueueProvider.getToCoreMsgConsumer(); |
||||
|
this.actorContext = actorContext; |
||||
|
} |
||||
|
|
||||
|
@PostConstruct |
||||
|
public void init() { |
||||
|
this.consumer.subscribe(); |
||||
|
this.mainConsumerExecutor = Executors.newSingleThreadExecutor(ThingsBoardThreadFactory.forName("tb-core-consumer")); |
||||
|
} |
||||
|
|
||||
|
@EventListener(ApplicationReadyEvent.class) |
||||
|
public void onApplicationEvent(ApplicationReadyEvent event) { |
||||
|
mainConsumerExecutor.execute(() -> { |
||||
|
while (!stopped) { |
||||
|
try { |
||||
|
List<TbProtoQueueMsg<TransportProtos.ToCoreMsg>> msgs = consumer.poll(pollDuration); |
||||
|
ConcurrentMap<UUID, TbProtoQueueMsg<TransportProtos.ToCoreMsg>> ackMap = msgs.stream().collect( |
||||
|
Collectors.toConcurrentMap(s -> UUID.randomUUID(), Function.identity())); |
||||
|
CountDownLatch processingTimeoutLatch = new CountDownLatch(1); |
||||
|
ackMap.forEach((id, msg) -> { |
||||
|
TbMsgCallback callback = new MsgPackCallback<>(id, processingTimeoutLatch, ackMap); |
||||
|
try { |
||||
|
TransportProtos.ToCoreMsg toCoreMsg = msg.getValue(); |
||||
|
log.trace("Forwarding message to rule engine {}", toCoreMsg); |
||||
|
if (toCoreMsg.hasToDeviceActorMsg()) { |
||||
|
forwardToDeviceActor(toCoreMsg.getToDeviceActorMsg(), callback); |
||||
|
} else { |
||||
|
callback.onSuccess(); |
||||
|
} |
||||
|
} catch (Throwable e) { |
||||
|
callback.onFailure(e); |
||||
|
} |
||||
|
}); |
||||
|
if (!processingTimeoutLatch.await(packProcessingTimeout, TimeUnit.MILLISECONDS)) { |
||||
|
ackMap.forEach((id, msg) -> log.warn("[{}] Timeout to process message: {}", id, msg.getValue())); |
||||
|
} |
||||
|
consumer.commit(); |
||||
|
} catch (Exception e) { |
||||
|
log.warn("Failed to obtain messages from queue.", e); |
||||
|
try { |
||||
|
Thread.sleep(pollDuration); |
||||
|
} catch (InterruptedException e2) { |
||||
|
log.trace("Failed to wait until the server has capacity to handle new requests", e2); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
private void forwardToDeviceActor(TransportProtos.TransportToDeviceActorMsg toDeviceActorMsg, TbMsgCallback callback) { |
||||
|
if (statsEnabled) { |
||||
|
stats.log(toDeviceActorMsg); |
||||
|
} |
||||
|
actorContext.getAppActor().tell(new TransportToDeviceActorMsgWrapper(toDeviceActorMsg, callback), ActorRef.noSender()); |
||||
|
} |
||||
|
|
||||
|
@Scheduled(fixedDelayString = "${queue.core.stats.print_interval_ms}") |
||||
|
public void printStats() { |
||||
|
if (statsEnabled) { |
||||
|
stats.printStats(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@PreDestroy |
||||
|
public void destroy() { |
||||
|
stopped = true; |
||||
|
if (consumer != null) { |
||||
|
consumer.unsubscribe(); |
||||
|
} |
||||
|
if (mainConsumerExecutor != null) { |
||||
|
mainConsumerExecutor.shutdownNow(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,70 @@ |
|||||
|
/** |
||||
|
* 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.gen.transport.TransportProtos; |
||||
|
|
||||
|
import java.util.concurrent.atomic.AtomicInteger; |
||||
|
|
||||
|
@Slf4j |
||||
|
public class TbCoreConsumerStats { |
||||
|
|
||||
|
private final AtomicInteger totalCounter = new AtomicInteger(0); |
||||
|
private final AtomicInteger sessionEventCounter = new AtomicInteger(0); |
||||
|
private final AtomicInteger getAttributesCounter = new AtomicInteger(0); |
||||
|
private final AtomicInteger subscribeToAttributesCounter = new AtomicInteger(0); |
||||
|
private final AtomicInteger subscribeToRPCCounter = new AtomicInteger(0); |
||||
|
private final AtomicInteger toDeviceRPCCallResponseCounter = new AtomicInteger(0); |
||||
|
private final AtomicInteger subscriptionInfoCounter = new AtomicInteger(0); |
||||
|
private final AtomicInteger claimDeviceCounter = new AtomicInteger(0); |
||||
|
|
||||
|
public void log(TransportProtos.TransportToDeviceActorMsg msg) { |
||||
|
totalCounter.incrementAndGet(); |
||||
|
if (msg.hasSessionEvent()) { |
||||
|
sessionEventCounter.incrementAndGet(); |
||||
|
} |
||||
|
if (msg.hasGetAttributes()) { |
||||
|
getAttributesCounter.incrementAndGet(); |
||||
|
} |
||||
|
if (msg.hasSubscribeToAttributes()) { |
||||
|
subscribeToAttributesCounter.incrementAndGet(); |
||||
|
} |
||||
|
if (msg.hasSubscribeToRPC()) { |
||||
|
subscribeToRPCCounter.incrementAndGet(); |
||||
|
} |
||||
|
if (msg.hasToDeviceRPCCallResponse()) { |
||||
|
toDeviceRPCCallResponseCounter.incrementAndGet(); |
||||
|
} |
||||
|
if (msg.hasSubscriptionInfo()) { |
||||
|
subscriptionInfoCounter.incrementAndGet(); |
||||
|
} |
||||
|
if (msg.hasClaimDevice()) { |
||||
|
claimDeviceCounter.incrementAndGet(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public void printStats() { |
||||
|
int total = totalCounter.getAndSet(0); |
||||
|
if (total > 0) { |
||||
|
log.info("Transport total [{}] sessionEvents [{}] getAttr [{}] subToAttr [{}] subToRpc [{}] toDevRpc [{}] subInfo [{}] claimDevice [{}]", |
||||
|
total, sessionEventCounter.getAndSet(0), |
||||
|
getAttributesCounter.getAndSet(0), subscribeToAttributesCounter.getAndSet(0), |
||||
|
subscribeToRPCCounter.getAndSet(0), toDeviceRPCCallResponseCounter.getAndSet(0), |
||||
|
subscriptionInfoCounter.getAndSet(0), claimDeviceCounter.getAndSet(0)); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,5 @@ |
|||||
|
package org.thingsboard.server.service.queue; |
||||
|
|
||||
|
public interface TbRuleEngineConsumerService { |
||||
|
|
||||
|
} |
||||
Loading…
Reference in new issue