Browse Source

created in memory queue

pull/2516/head
YevhenBondarenko 7 years ago
committed by Andrew Shvayka
parent
commit
4ad4fe11da
  1. 4
      application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java
  2. 86
      application/src/main/java/org/thingsboard/server/service/script/RemoteJsInvokeService.java
  3. 7
      application/src/main/java/org/thingsboard/server/service/script/RemoteJsRequestEncoder.java
  4. 10
      application/src/main/java/org/thingsboard/server/service/script/RemoteJsResponseDecoder.java
  5. 25
      application/src/main/java/org/thingsboard/server/service/transport/LocalTransportApiService.java
  6. 56
      application/src/main/java/org/thingsboard/server/service/transport/RemoteRuleEngineTransportService.java
  7. 28
      application/src/main/java/org/thingsboard/server/service/transport/RemoteTransportApiService.java
  8. 6
      application/src/main/java/org/thingsboard/server/service/transport/ToRuleEngineMsgDecoder.java
  9. 5
      application/src/main/java/org/thingsboard/server/service/transport/TransportApiService.java
  10. 2
      common/queue/src/main/java/org/thingsboard/server/TbQueueConsumer.java
  11. 4
      common/queue/src/main/java/org/thingsboard/server/TbQueueMsgHeaders.java
  12. 7
      common/queue/src/main/java/org/thingsboard/server/common/DefaultTbQueueMsgHeaders.java
  13. 4
      common/queue/src/main/java/org/thingsboard/server/common/TbProtoQueueMsg.java
  14. 39
      common/queue/src/main/java/org/thingsboard/server/kafka/KafkaTbQueueMsg.java
  15. 12
      common/queue/src/main/java/org/thingsboard/server/kafka/KafkaTbQueueMsgMetadata.java
  16. 9
      common/queue/src/main/java/org/thingsboard/server/kafka/TBKafkaAdmin.java
  17. 48
      common/queue/src/main/java/org/thingsboard/server/kafka/TBKafkaConsumerTemplate.java
  18. 104
      common/queue/src/main/java/org/thingsboard/server/kafka/TBKafkaProducerTemplate.java
  19. 4
      common/queue/src/main/java/org/thingsboard/server/kafka/TbKafkaDecoder.java
  20. 45
      common/queue/src/main/java/org/thingsboard/server/memory/InMemoryStorage.java
  21. 42
      common/queue/src/main/java/org/thingsboard/server/memory/InMemoryTbQueueConsumer.java
  22. 43
      common/queue/src/main/java/org/thingsboard/server/memory/InMemoryTbQueueProducer.java
  23. 2
      common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java
  24. 6
      common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/ToTransportMsgResponseDecoder.java
  25. 6
      common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/TransportApiResponseDecoder.java
  26. 13
      dao/src/main/java/org/thingsboard/server/dao/entity/BaseEntityService.java
  27. 38
      dao/src/main/java/org/thingsboard/server/dao/relation/BaseRelationService.java
  28. 3
      dao/src/main/java/org/thingsboard/server/dao/sqlts/timescale/TimescaleTimeseriesDao.java
  29. 5
      dao/src/main/java/org/thingsboard/server/dao/timeseries/CassandraBaseTimeseriesDao.java

4
application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java

@ -20,9 +20,9 @@ import com.datastax.driver.core.utils.UUIDs;
import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.protobuf.InvalidProtocolBufferException; import com.google.protobuf.InvalidProtocolBufferException;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.CollectionUtils;
@ -292,7 +292,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor {
.build(); .build();
sendToTransport(responseMsg, sessionInfo); sendToTransport(responseMsg, sessionInfo);
} }
}); }, MoreExecutors.directExecutor());
} }
private ListenableFuture<List<List<AttributeKvEntry>>> getAttributesKvEntries(GetAttributeRequestMsg request) { private ListenableFuture<List<List<AttributeKvEntry>>> getAttributesKvEntries(GetAttributeRequestMsg request) {

86
application/src/main/java/org/thingsboard/server/service/script/RemoteJsInvokeService.java

@ -25,11 +25,10 @@ import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.scheduling.annotation.Scheduled; import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.thingsboard.server.TbQueueProducer;
import org.thingsboard.server.common.DefaultTbQueueRequestTemplate;
import org.thingsboard.server.common.TbProtoQueueMsg;
import org.thingsboard.server.gen.js.JsInvokeProtos; import org.thingsboard.server.gen.js.JsInvokeProtos;
import org.thingsboard.server.kafka.TBKafkaConsumerTemplate;
import org.thingsboard.server.kafka.TBKafkaProducerTemplate;
import org.thingsboard.server.kafka.TbKafkaRequestTemplate;
import org.thingsboard.server.kafka.TbKafkaSettings;
import org.thingsboard.server.kafka.TbNodeIdProvider; import org.thingsboard.server.kafka.TbNodeIdProvider;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@ -40,7 +39,6 @@ import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
@Slf4j @Slf4j
@ConditionalOnProperty(prefix = "js", value = "evaluator", havingValue = "remote", matchIfMissing = true) @ConditionalOnProperty(prefix = "js", value = "evaluator", havingValue = "remote", matchIfMissing = true)
@ -99,42 +97,43 @@ public class RemoteJsInvokeService extends AbstractJsInvokeService {
} }
} }
private TbKafkaRequestTemplate<JsInvokeProtos.RemoteJsRequest, JsInvokeProtos.RemoteJsResponse> kafkaTemplate; private DefaultTbQueueRequestTemplate<TbProtoQueueMsg<JsInvokeProtos.RemoteJsRequest>, TbProtoQueueMsg<JsInvokeProtos.RemoteJsResponse>> defaultTemplate;
private Map<UUID, String> scriptIdToBodysMap = new ConcurrentHashMap<>(); private Map<UUID, String> scriptIdToBodysMap = new ConcurrentHashMap<>();
@PostConstruct @PostConstruct
public void init() { public void init() {
TBKafkaProducerTemplate.TBKafkaProducerTemplateBuilder<JsInvokeProtos.RemoteJsRequest> requestBuilder = TBKafkaProducerTemplate.builder(); // TBKafkaProducerTemplate.TBKafkaProducerTemplateBuilder<TbProtoQueueMsg<JsInvokeProtos.RemoteJsRequest>> requestBuilder = TBKafkaProducerTemplate.builder();
requestBuilder.settings(kafkaSettings); // requestBuilder.settings(kafkaSettings);
requestBuilder.clientId("producer-js-invoke-" + nodeIdProvider.getNodeId()); // requestBuilder.clientId("producer-js-invoke-" + nodeIdProvider.getNodeId());
requestBuilder.defaultTopic(requestTopic); // requestBuilder.defaultTopic(requestTopic);
requestBuilder.encoder(new RemoteJsRequestEncoder()); // requestBuilder.encoder(new RemoteJsRequestEncoder());
TbQueueProducer<TbProtoQueueMsg<JsInvokeProtos.RemoteJsRequest>> producer;
TBKafkaConsumerTemplate.TBKafkaConsumerTemplateBuilder<JsInvokeProtos.RemoteJsResponse> responseBuilder = TBKafkaConsumerTemplate.builder();
responseBuilder.settings(kafkaSettings); // TBKafkaConsumerTemplate.TBKafkaConsumerTemplateBuilder<JsInvokeProtos.RemoteJsResponse> responseBuilder = TBKafkaConsumerTemplate.builder();
responseBuilder.topic(responseTopicPrefix + "." + nodeIdProvider.getNodeId()); // responseBuilder.settings(kafkaSettings);
responseBuilder.clientId("js-" + nodeIdProvider.getNodeId()); // responseBuilder.topic(responseTopicPrefix + "." + nodeIdProvider.getNodeId());
responseBuilder.groupId("rule-engine-node-" + nodeIdProvider.getNodeId()); // responseBuilder.clientId("js-" + nodeIdProvider.getNodeId());
responseBuilder.autoCommit(true); // responseBuilder.groupId("rule-engine-node-" + nodeIdProvider.getNodeId());
responseBuilder.autoCommitIntervalMs(autoCommitInterval); // responseBuilder.autoCommit(true);
responseBuilder.decoder(new RemoteJsResponseDecoder()); // responseBuilder.autoCommitIntervalMs(autoCommitInterval);
responseBuilder.requestIdExtractor((response) -> new UUID(response.getRequestIdMSB(), response.getRequestIdLSB())); // responseBuilder.decoder(new RemoteJsResponseDecoder());
// responseBuilder.requestIdExtractor((response) -> new UUID(response.getRequestIdMSB(), response.getRequestIdLSB()));
TbKafkaRequestTemplate.TbKafkaRequestTemplateBuilder //
<JsInvokeProtos.RemoteJsRequest, JsInvokeProtos.RemoteJsResponse> builder = TbKafkaRequestTemplate.builder(); // TbKafkaRequestTemplate.TbKafkaRequestTemplateBuilder
builder.requestTemplate(requestBuilder.build()); // <JsInvokeProtos.RemoteJsRequest, JsInvokeProtos.RemoteJsResponse> builder = TbKafkaRequestTemplate.builder();
builder.responseTemplate(responseBuilder.build()); // builder.requestTemplate(requestBuilder.build());
builder.maxPendingRequests(maxPendingRequests); // builder.responseTemplate(responseBuilder.build());
builder.maxRequestTimeout(maxRequestsTimeout); // builder.maxPendingRequests(maxPendingRequests);
builder.pollInterval(responsePollDuration); // builder.maxRequestTimeout(maxRequestsTimeout);
kafkaTemplate = builder.build(); // builder.pollInterval(responsePollDuration);
kafkaTemplate.init(); // defaultTemplate = builder.build();
// defaultTemplate.init();
} }
@PreDestroy @PreDestroy
public void destroy() { public void destroy() {
if (kafkaTemplate != null) { if (defaultTemplate != null) {
kafkaTemplate.stop(); defaultTemplate.stop();
} }
} }
@ -151,11 +150,12 @@ public class RemoteJsInvokeService extends AbstractJsInvokeService {
.build(); .build();
log.trace("Post compile request for scriptId [{}]", scriptId); log.trace("Post compile request for scriptId [{}]", scriptId);
ListenableFuture<JsInvokeProtos.RemoteJsResponse> future = kafkaTemplate.post(UUID.randomUUID().toString(), jsRequestWrapper); ListenableFuture<TbProtoQueueMsg<JsInvokeProtos.RemoteJsResponse>> future = defaultTemplate.send(new TbProtoQueueMsg<>(UUID.randomUUID(), jsRequestWrapper));
kafkaPushedMsgs.incrementAndGet(); kafkaPushedMsgs.incrementAndGet();
Futures.addCallback(future, new FutureCallback<JsInvokeProtos.RemoteJsResponse>() { Futures.addCallback(future, new FutureCallback<TbProtoQueueMsg<JsInvokeProtos.RemoteJsResponse>>() {
@Override @Override
public void onSuccess(@Nullable JsInvokeProtos.RemoteJsResponse result) { public void onSuccess(@Nullable TbProtoQueueMsg<JsInvokeProtos.RemoteJsResponse> result) {
kafkaEvalMsgs.incrementAndGet(); kafkaEvalMsgs.incrementAndGet();
} }
@ -168,7 +168,7 @@ public class RemoteJsInvokeService extends AbstractJsInvokeService {
} }
}); });
return Futures.transform(future, response -> { return Futures.transform(future, response -> {
JsInvokeProtos.JsCompileResponse compilationResult = response.getCompileResponse(); JsInvokeProtos.JsCompileResponse compilationResult = response.getValue().getCompileResponse();
UUID compiledScriptId = new UUID(compilationResult.getScriptIdMSB(), compilationResult.getScriptIdLSB()); UUID compiledScriptId = new UUID(compilationResult.getScriptIdMSB(), compilationResult.getScriptIdLSB());
if (compilationResult.getSuccess()) { if (compilationResult.getSuccess()) {
scriptIdToNameMap.put(scriptId, functionName); scriptIdToNameMap.put(scriptId, functionName);
@ -202,11 +202,11 @@ public class RemoteJsInvokeService extends AbstractJsInvokeService {
.setInvokeRequest(jsRequestBuilder.build()) .setInvokeRequest(jsRequestBuilder.build())
.build(); .build();
ListenableFuture<JsInvokeProtos.RemoteJsResponse> future = kafkaTemplate.post(UUID.randomUUID().toString(), jsRequestWrapper); ListenableFuture<TbProtoQueueMsg<JsInvokeProtos.RemoteJsResponse>> future = defaultTemplate.send(new TbProtoQueueMsg<>(UUID.randomUUID(), jsRequestWrapper));
kafkaPushedMsgs.incrementAndGet(); kafkaPushedMsgs.incrementAndGet();
Futures.addCallback(future, new FutureCallback<JsInvokeProtos.RemoteJsResponse>() { Futures.addCallback(future, new FutureCallback<TbProtoQueueMsg<JsInvokeProtos.RemoteJsResponse>>() {
@Override @Override
public void onSuccess(@Nullable JsInvokeProtos.RemoteJsResponse result) { public void onSuccess(@Nullable TbProtoQueueMsg<JsInvokeProtos.RemoteJsResponse> result) {
kafkaInvokeMsgs.incrementAndGet(); kafkaInvokeMsgs.incrementAndGet();
} }
@ -219,7 +219,7 @@ public class RemoteJsInvokeService extends AbstractJsInvokeService {
} }
}); });
return Futures.transform(future, response -> { return Futures.transform(future, response -> {
JsInvokeProtos.JsInvokeResponse invokeResult = response.getInvokeResponse(); JsInvokeProtos.JsInvokeResponse invokeResult = response.getValue().getInvokeResponse();
if (invokeResult.getSuccess()) { if (invokeResult.getSuccess()) {
return invokeResult.getResult(); return invokeResult.getResult();
} else { } else {
@ -240,8 +240,8 @@ public class RemoteJsInvokeService extends AbstractJsInvokeService {
.setReleaseRequest(jsRequest) .setReleaseRequest(jsRequest)
.build(); .build();
ListenableFuture<JsInvokeProtos.RemoteJsResponse> future = kafkaTemplate.post(UUID.randomUUID().toString(), jsRequestWrapper); ListenableFuture<TbProtoQueueMsg<JsInvokeProtos.RemoteJsResponse>> future = defaultTemplate.send(new TbProtoQueueMsg<>(UUID.randomUUID(), jsRequestWrapper));
JsInvokeProtos.RemoteJsResponse response = future.get(); JsInvokeProtos.RemoteJsResponse response = future.get().getValue();
JsInvokeProtos.JsReleaseResponse compilationResult = response.getReleaseResponse(); JsInvokeProtos.JsReleaseResponse compilationResult = response.getReleaseResponse();
UUID compiledScriptId = new UUID(compilationResult.getScriptIdMSB(), compilationResult.getScriptIdLSB()); UUID compiledScriptId = new UUID(compilationResult.getScriptIdMSB(), compilationResult.getScriptIdLSB());

7
application/src/main/java/org/thingsboard/server/service/script/RemoteJsRequestEncoder.java

@ -17,6 +17,7 @@ package org.thingsboard.server.service.script;
import com.google.protobuf.InvalidProtocolBufferException; import com.google.protobuf.InvalidProtocolBufferException;
import com.google.protobuf.util.JsonFormat; import com.google.protobuf.util.JsonFormat;
import org.thingsboard.server.common.TbProtoQueueMsg;
import org.thingsboard.server.gen.js.JsInvokeProtos; import org.thingsboard.server.gen.js.JsInvokeProtos;
import org.thingsboard.server.kafka.TbKafkaEncoder; import org.thingsboard.server.kafka.TbKafkaEncoder;
@ -25,11 +26,11 @@ import java.nio.charset.StandardCharsets;
/** /**
* Created by ashvayka on 25.09.18. * Created by ashvayka on 25.09.18.
*/ */
public class RemoteJsRequestEncoder implements TbKafkaEncoder<JsInvokeProtos.RemoteJsRequest> { public class RemoteJsRequestEncoder implements TbKafkaEncoder<TbProtoQueueMsg<JsInvokeProtos.RemoteJsRequest>> {
@Override @Override
public byte[] encode(JsInvokeProtos.RemoteJsRequest value) { public byte[] encode(TbProtoQueueMsg<JsInvokeProtos.RemoteJsRequest> value) {
try { try {
return JsonFormat.printer().print(value).getBytes(StandardCharsets.UTF_8); return JsonFormat.printer().print(value.getValue()).getBytes(StandardCharsets.UTF_8);
} catch (InvalidProtocolBufferException e) { } catch (InvalidProtocolBufferException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }

10
application/src/main/java/org/thingsboard/server/service/script/RemoteJsResponseDecoder.java

@ -16,6 +16,8 @@
package org.thingsboard.server.service.script; package org.thingsboard.server.service.script;
import com.google.protobuf.util.JsonFormat; import com.google.protobuf.util.JsonFormat;
import org.thingsboard.server.TbQueueMsg;
import org.thingsboard.server.common.TbProtoQueueMsg;
import org.thingsboard.server.gen.js.JsInvokeProtos; import org.thingsboard.server.gen.js.JsInvokeProtos;
import org.thingsboard.server.kafka.TbKafkaDecoder; import org.thingsboard.server.kafka.TbKafkaDecoder;
@ -25,12 +27,12 @@ import java.nio.charset.StandardCharsets;
/** /**
* Created by ashvayka on 25.09.18. * Created by ashvayka on 25.09.18.
*/ */
public class RemoteJsResponseDecoder implements TbKafkaDecoder<JsInvokeProtos.RemoteJsResponse> { public class RemoteJsResponseDecoder implements TbKafkaDecoder<TbProtoQueueMsg<JsInvokeProtos.RemoteJsResponse>> {
@Override @Override
public JsInvokeProtos.RemoteJsResponse decode(byte[] data) throws IOException { public TbProtoQueueMsg<JsInvokeProtos.RemoteJsResponse> decode(TbQueueMsg msg) throws IOException {
JsInvokeProtos.RemoteJsResponse.Builder builder = JsInvokeProtos.RemoteJsResponse.newBuilder(); JsInvokeProtos.RemoteJsResponse.Builder builder = JsInvokeProtos.RemoteJsResponse.newBuilder();
JsonFormat.parser().ignoringUnknownFields().merge(new String(data, StandardCharsets.UTF_8), builder); JsonFormat.parser().ignoringUnknownFields().merge(new String(msg.getData(), StandardCharsets.UTF_8), builder);
return builder.build(); return new TbProtoQueueMsg<>(msg.getKey(), builder.build(), msg.getHeaders());
} }
} }

25
application/src/main/java/org/thingsboard/server/service/transport/LocalTransportApiService.java

@ -21,10 +21,9 @@ import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import org.thingsboard.server.common.TbProtoQueueMsg;
import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
@ -42,19 +41,10 @@ import org.thingsboard.server.gen.transport.TransportProtos.TransportApiResponse
import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceCredentialsResponseMsg; import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceCredentialsResponseMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceTokenRequestMsg; import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceTokenRequestMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceX509CertRequestMsg; import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceX509CertRequestMsg;
import org.thingsboard.server.kafka.TBKafkaConsumerTemplate;
import org.thingsboard.server.kafka.TBKafkaProducerTemplate;
import org.thingsboard.server.kafka.TbKafkaResponseTemplate;
import org.thingsboard.server.kafka.TbKafkaSettings;
import org.thingsboard.server.service.cluster.discovery.DiscoveryService;
import org.thingsboard.server.service.executors.DbCallbackExecutorService; import org.thingsboard.server.service.executors.DbCallbackExecutorService;
import org.thingsboard.server.service.state.DeviceStateService; import org.thingsboard.server.service.state.DeviceStateService;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantLock;
/** /**
@ -84,17 +74,18 @@ public class LocalTransportApiService implements TransportApiService {
private ReentrantLock deviceCreationLock = new ReentrantLock(); private ReentrantLock deviceCreationLock = new ReentrantLock();
@Override @Override
public ListenableFuture<TransportApiResponseMsg> handle(TransportApiRequestMsg transportApiRequestMsg) { public ListenableFuture<TbProtoQueueMsg<TransportApiResponseMsg>> handle(TbProtoQueueMsg<TransportApiRequestMsg> tbProtoQueueMsg) {
TransportApiRequestMsg transportApiRequestMsg = tbProtoQueueMsg.getValue();
if (transportApiRequestMsg.hasValidateTokenRequestMsg()) { if (transportApiRequestMsg.hasValidateTokenRequestMsg()) {
ValidateDeviceTokenRequestMsg msg = transportApiRequestMsg.getValidateTokenRequestMsg(); ValidateDeviceTokenRequestMsg msg = transportApiRequestMsg.getValidateTokenRequestMsg();
return validateCredentials(msg.getToken(), DeviceCredentialsType.ACCESS_TOKEN); return Futures.transform(validateCredentials(msg.getToken(), DeviceCredentialsType.ACCESS_TOKEN), value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders()));
} else if (transportApiRequestMsg.hasValidateX509CertRequestMsg()) { } else if (transportApiRequestMsg.hasValidateX509CertRequestMsg()) {
ValidateDeviceX509CertRequestMsg msg = transportApiRequestMsg.getValidateX509CertRequestMsg(); ValidateDeviceX509CertRequestMsg msg = transportApiRequestMsg.getValidateX509CertRequestMsg();
return validateCredentials(msg.getHash(), DeviceCredentialsType.X509_CERTIFICATE); return Futures.transform(validateCredentials(msg.getHash(), DeviceCredentialsType.X509_CERTIFICATE), value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders()));
} else if (transportApiRequestMsg.hasGetOrCreateDeviceRequestMsg()) { } else if (transportApiRequestMsg.hasGetOrCreateDeviceRequestMsg()) {
return handle(transportApiRequestMsg.getGetOrCreateDeviceRequestMsg()); return Futures.transform(handle(transportApiRequestMsg.getGetOrCreateDeviceRequestMsg()), value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders()));
} }
return getEmptyTransportApiResponseFuture(); return Futures.transform(getEmptyTransportApiResponseFuture(), value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders()));
} }
private ListenableFuture<TransportApiResponseMsg> validateCredentials(String credentialsId, DeviceCredentialsType credentialsType) { private ListenableFuture<TransportApiResponseMsg> validateCredentials(String credentialsId, DeviceCredentialsType credentialsType) {
@ -145,7 +136,7 @@ public class LocalTransportApiService implements TransportApiService {
try { try {
ValidateDeviceCredentialsResponseMsg.Builder builder = ValidateDeviceCredentialsResponseMsg.newBuilder(); ValidateDeviceCredentialsResponseMsg.Builder builder = ValidateDeviceCredentialsResponseMsg.newBuilder();
builder.setDeviceInfo(getDeviceInfoProto(device)); builder.setDeviceInfo(getDeviceInfoProto(device));
if(!StringUtils.isEmpty(credentials.getCredentialsValue())){ if (!StringUtils.isEmpty(credentials.getCredentialsValue())) {
builder.setCredentialsBody(credentials.getCredentialsValue()); builder.setCredentialsBody(credentials.getCredentialsValue());
} }
return TransportApiResponseMsg.newBuilder() return TransportApiResponseMsg.newBuilder()

56
application/src/main/java/org/thingsboard/server/service/transport/RemoteRuleEngineTransportService.java

@ -22,9 +22,6 @@ import io.github.bucket4j.Bucket4j;
import io.github.bucket4j.local.LocalBucket; import io.github.bucket4j.local.LocalBucket;
import io.github.bucket4j.local.LocalBucketBuilder; import io.github.bucket4j.local.LocalBucketBuilder;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.kafka.clients.consumer.ConsumerRecords;
import org.apache.kafka.clients.producer.Callback;
import org.apache.kafka.clients.producer.RecordMetadata;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
@ -33,15 +30,17 @@ import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Scheduled; import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.thingsboard.common.util.ThingsBoardThreadFactory; import org.thingsboard.common.util.ThingsBoardThreadFactory;
import org.thingsboard.server.TbQueueCallback;
import org.thingsboard.server.TbQueueConsumer;
import org.thingsboard.server.TbQueueMsgMetadata;
import org.thingsboard.server.TbQueueProducer;
import org.thingsboard.server.actors.ActorSystemContext; import org.thingsboard.server.actors.ActorSystemContext;
import org.thingsboard.server.common.TbProtoQueueMsg;
import org.thingsboard.server.common.msg.cluster.ServerAddress; import org.thingsboard.server.common.msg.cluster.ServerAddress;
import org.thingsboard.server.gen.transport.TransportProtos.DeviceActorToTransportMsg; import org.thingsboard.server.gen.transport.TransportProtos.DeviceActorToTransportMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg;
import org.thingsboard.server.gen.transport.TransportProtos.TransportToDeviceActorMsg; import org.thingsboard.server.gen.transport.TransportProtos.TransportToDeviceActorMsg;
import org.thingsboard.server.kafka.TBKafkaConsumerTemplate;
import org.thingsboard.server.kafka.TBKafkaProducerTemplate;
import org.thingsboard.server.kafka.TbKafkaSettings;
import org.thingsboard.server.kafka.TbNodeIdProvider; import org.thingsboard.server.kafka.TbNodeIdProvider;
import org.thingsboard.server.service.cluster.routing.ClusterRoutingService; import org.thingsboard.server.service.cluster.routing.ClusterRoutingService;
import org.thingsboard.server.service.cluster.rpc.ClusterRpcService; import org.thingsboard.server.service.cluster.rpc.ClusterRpcService;
@ -51,6 +50,7 @@ import org.thingsboard.server.service.transport.msg.TransportToDeviceActorMsgWra
import javax.annotation.PostConstruct; import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy; import javax.annotation.PreDestroy;
import java.time.Duration; import java.time.Duration;
import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
@ -84,9 +84,9 @@ public class RemoteRuleEngineTransportService implements RuleEngineTransportServ
@Value("${transport.remote.rule_engine.stats.enabled:false}") @Value("${transport.remote.rule_engine.stats.enabled:false}")
private boolean statsEnabled; private boolean statsEnabled;
@Autowired // @Autowired
private TbKafkaSettings kafkaSettings; // private TbKafkaSettings kafkaSettings;
//
@Autowired @Autowired
private TbNodeIdProvider nodeIdProvider; private TbNodeIdProvider nodeIdProvider;
@ -101,8 +101,9 @@ public class RemoteRuleEngineTransportService implements RuleEngineTransportServ
@Autowired @Autowired
private DataDecodingEncodingService encodingService; private DataDecodingEncodingService encodingService;
private TBKafkaConsumerTemplate<ToRuleEngineMsg> ruleEngineConsumer; private TbQueueConsumer<TbProtoQueueMsg<ToRuleEngineMsg>> ruleEngineConsumer;
private TBKafkaProducerTemplate<ToTransportMsg> notificationsProducer;
private TbQueueProducer<TbProtoQueueMsg<ToTransportMsg>> notificationsProducer;
private ExecutorService mainConsumerExecutor = Executors.newSingleThreadExecutor(ThingsBoardThreadFactory.forName("tb-main-consumer")); private ExecutorService mainConsumerExecutor = Executors.newSingleThreadExecutor(ThingsBoardThreadFactory.forName("tb-main-consumer"));
@ -146,8 +147,8 @@ public class RemoteRuleEngineTransportService implements RuleEngineTransportServ
mainConsumerExecutor.execute(() -> { mainConsumerExecutor.execute(() -> {
while (!stopped) { while (!stopped) {
try { try {
ConsumerRecords<String, byte[]> records = ruleEngineConsumer.poll(Duration.ofMillis(pollDuration)); List<TbProtoQueueMsg<ToRuleEngineMsg>> msgs = ruleEngineConsumer.poll(pollDuration);
int recordsCount = records.count(); int recordsCount = msgs.size();
if (recordsCount > 0) { if (recordsCount > 0) {
while (!blockingPollRateBucket.tryConsume(recordsCount, TimeUnit.SECONDS.toNanos(5))) { while (!blockingPollRateBucket.tryConsume(recordsCount, TimeUnit.SECONDS.toNanos(5))) {
log.info("Rule Engine consumer is busy. Required tokens: [{}]. Available tokens: [{}].", recordsCount, pollRateBucket.getAvailableTokens()); log.info("Rule Engine consumer is busy. Required tokens: [{}]. Available tokens: [{}].", recordsCount, pollRateBucket.getAvailableTokens());
@ -155,9 +156,9 @@ public class RemoteRuleEngineTransportService implements RuleEngineTransportServ
} }
log.trace("Processing {} records", recordsCount); log.trace("Processing {} records", recordsCount);
} }
records.forEach(record -> { msgs.forEach(msg -> {
try { try {
ToRuleEngineMsg toRuleEngineMsg = ruleEngineConsumer.decode(record); ToRuleEngineMsg toRuleEngineMsg = msg.getValue();
log.trace("Forwarding message to rule engine {}", toRuleEngineMsg); log.trace("Forwarding message to rule engine {}", toRuleEngineMsg);
if (toRuleEngineMsg.hasToDeviceActorMsg()) { if (toRuleEngineMsg.hasToDeviceActorMsg()) {
forwardToDeviceActor(toRuleEngineMsg.getToDeviceActorMsg()); forwardToDeviceActor(toRuleEngineMsg.getToDeviceActorMsg());
@ -196,7 +197,8 @@ public class RemoteRuleEngineTransportService implements RuleEngineTransportServ
UUID sessionId = new UUID(msg.getSessionIdMSB(), msg.getSessionIdLSB()); UUID sessionId = new UUID(msg.getSessionIdMSB(), msg.getSessionIdLSB());
ToTransportMsg transportMsg = ToTransportMsg.newBuilder().setToDeviceSessionMsg(msg).build(); ToTransportMsg transportMsg = ToTransportMsg.newBuilder().setToDeviceSessionMsg(msg).build();
log.trace("[{}][{}] Pushing session data to topic: {}", topic, sessionId, transportMsg); log.trace("[{}][{}] Pushing session data to topic: {}", topic, sessionId, transportMsg);
notificationsProducer.send(topic, sessionId.toString(), transportMsg, new QueueCallbackAdaptor(onSuccess, onFailure)); TbProtoQueueMsg<ToTransportMsg> queueMsg = new TbProtoQueueMsg<>(sessionId, transportMsg);
notificationsProducer.send(topic, queueMsg, new QueueCallbackAdaptor(onSuccess, onFailure));
} }
private void forwardToDeviceActor(TransportToDeviceActorMsg toDeviceActorMsg) { private void forwardToDeviceActor(TransportToDeviceActorMsg toDeviceActorMsg) {
@ -225,7 +227,7 @@ public class RemoteRuleEngineTransportService implements RuleEngineTransportServ
} }
} }
private static class QueueCallbackAdaptor implements Callback { private static class QueueCallbackAdaptor implements TbQueueCallback {
private final Runnable onSuccess; private final Runnable onSuccess;
private final Consumer<Throwable> onFailure; private final Consumer<Throwable> onFailure;
@ -235,17 +237,17 @@ public class RemoteRuleEngineTransportService implements RuleEngineTransportServ
} }
@Override @Override
public void onCompletion(RecordMetadata metadata, Exception exception) { public void onSuccess(TbQueueMsgMetadata metadata) {
if (exception == null) { if (onSuccess != null) {
if (onSuccess != null) { onSuccess.run();
onSuccess.run();
}
} else {
if (onFailure != null) {
onFailure.accept(exception);
}
} }
} }
}
@Override
public void onFailure(Throwable t) {
if (onFailure != null) {
onFailure.accept(t);
}
}
}
} }

28
application/src/main/java/org/thingsboard/server/service/transport/RemoteTransportApiService.java

@ -22,9 +22,16 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.event.ApplicationReadyEvent; import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.EventListener; import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.thingsboard.server.TbQueueConsumer;
import org.thingsboard.server.TbQueueProducer;
import org.thingsboard.server.TbQueueRequestTemplate;
import org.thingsboard.server.TbQueueResponseTemplate;
import org.thingsboard.server.common.DefaultTbQueueRequestTemplate;
import org.thingsboard.server.common.DefaultTbQueueResponseTemplate;
import org.thingsboard.server.common.TbProtoQueueMsg;
import org.thingsboard.server.gen.transport.TransportProtos.TransportApiRequestMsg; import org.thingsboard.server.gen.transport.TransportProtos.TransportApiRequestMsg;
import org.thingsboard.server.gen.transport.TransportProtos.TransportApiResponseMsg; import org.thingsboard.server.gen.transport.TransportProtos.TransportApiResponseMsg;
import org.thingsboard.server.kafka.*; import org.thingsboard.server.kafka.TbNodeIdProvider;
import javax.annotation.PostConstruct; import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy; import javax.annotation.PreDestroy;
@ -49,9 +56,9 @@ public class RemoteTransportApiService {
@Value("${transport.remote.transport_api.request_auto_commit_interval}") @Value("${transport.remote.transport_api.request_auto_commit_interval}")
private int autoCommitInterval; private int autoCommitInterval;
@Autowired // @Autowired
private TbKafkaSettings kafkaSettings; // private TbKafkaSettings kafkaSettings;
//
@Autowired @Autowired
private TbNodeIdProvider nodeIdProvider; private TbNodeIdProvider nodeIdProvider;
@ -60,7 +67,7 @@ public class RemoteTransportApiService {
private ExecutorService transportCallbackExecutor; private ExecutorService transportCallbackExecutor;
private TbKafkaResponseTemplate<TransportApiRequestMsg, TransportApiResponseMsg> transportApiTemplate; private TbQueueResponseTemplate<TbProtoQueueMsg<TransportApiRequestMsg>, TbProtoQueueMsg<TransportApiResponseMsg>> transportApiTemplate;
@PostConstruct @PostConstruct
public void init() { public void init() {
@ -79,11 +86,14 @@ public class RemoteTransportApiService {
requestBuilder.autoCommit(true); requestBuilder.autoCommit(true);
requestBuilder.autoCommitIntervalMs(autoCommitInterval); requestBuilder.autoCommitIntervalMs(autoCommitInterval);
requestBuilder.decoder(new TransportApiRequestDecoder()); requestBuilder.decoder(new TransportApiRequestDecoder());
TbQueueProducer<TbProtoQueueMsg<TransportApiResponseMsg>> producer = null;
TbQueueConsumer<TbProtoQueueMsg<TransportApiRequestMsg>> consumer = null;
TbKafkaResponseTemplate.TbKafkaResponseTemplateBuilder DefaultTbQueueResponseTemplate.DefaultTbQueueResponseTemplateBuilder
<TransportApiRequestMsg, TransportApiResponseMsg> builder = TbKafkaResponseTemplate.builder(); <TbProtoQueueMsg<TransportApiRequestMsg>, TbProtoQueueMsg<TransportApiResponseMsg>> builder = DefaultTbQueueResponseTemplate.builder();
builder.requestTemplate(requestBuilder.build()); builder.requestTemplate(consumer);
builder.responseTemplate(responseBuilder.build()); builder.responseTemplate(producer);
builder.maxPendingRequests(maxPendingRequests); builder.maxPendingRequests(maxPendingRequests);
builder.requestTimeout(requestTimeout); builder.requestTimeout(requestTimeout);
builder.pollInterval(responsePollDuration); builder.pollInterval(responsePollDuration);

6
application/src/main/java/org/thingsboard/server/service/transport/ToRuleEngineMsgDecoder.java

@ -15,6 +15,7 @@
*/ */
package org.thingsboard.server.service.transport; package org.thingsboard.server.service.transport;
import org.thingsboard.server.TbQueueMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg;
import org.thingsboard.server.kafka.TbKafkaDecoder; import org.thingsboard.server.kafka.TbKafkaDecoder;
@ -24,8 +25,9 @@ import java.io.IOException;
* Created by ashvayka on 05.10.18. * Created by ashvayka on 05.10.18.
*/ */
public class ToRuleEngineMsgDecoder implements TbKafkaDecoder<ToRuleEngineMsg> { public class ToRuleEngineMsgDecoder implements TbKafkaDecoder<ToRuleEngineMsg> {
@Override @Override
public ToRuleEngineMsg decode(byte[] data) throws IOException { public ToRuleEngineMsg decode(TbQueueMsg msg) throws IOException {
return ToRuleEngineMsg.parseFrom(data); return ToRuleEngineMsg.parseFrom(msg.getData());
} }
} }

5
application/src/main/java/org/thingsboard/server/service/transport/TransportApiService.java

@ -15,11 +15,12 @@
*/ */
package org.thingsboard.server.service.transport; package org.thingsboard.server.service.transport;
import org.thingsboard.server.TbQueueHandler;
import org.thingsboard.server.common.TbProtoQueueMsg;
import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.kafka.TbKafkaHandler;
/** /**
* Created by ashvayka on 05.10.18. * Created by ashvayka on 05.10.18.
*/ */
public interface TransportApiService extends TbKafkaHandler<TransportProtos.TransportApiRequestMsg, TransportProtos.TransportApiResponseMsg> { public interface TransportApiService extends TbQueueHandler<TbProtoQueueMsg<TransportProtos.TransportApiRequestMsg>, TbProtoQueueMsg<TransportProtos.TransportApiResponseMsg>> {
} }

2
common/queue/src/main/java/org/thingsboard/server/TbQueueConsumer.java

@ -8,6 +8,8 @@ public interface TbQueueConsumer<T extends TbQueueMsg> {
void subscribe(); void subscribe();
void unsubscribe();
List<T> poll(long durationInMillis); List<T> poll(long durationInMillis);
void commit(); void commit();

4
common/queue/src/main/java/org/thingsboard/server/TbQueueMsgHeaders.java

@ -1,8 +1,12 @@
package org.thingsboard.server; package org.thingsboard.server;
import java.util.Map;
public interface TbQueueMsgHeaders { public interface TbQueueMsgHeaders {
byte[] put(String key, byte[] value); byte[] put(String key, byte[] value);
byte[] get(String key); byte[] get(String key);
Map<String, byte[]> getData();
} }

7
common/queue/src/main/java/org/thingsboard/server/common/DefaultTbQueueMsgHeaders.java

@ -7,7 +7,7 @@ import java.util.Map;
public class DefaultTbQueueMsgHeaders implements TbQueueMsgHeaders { public class DefaultTbQueueMsgHeaders implements TbQueueMsgHeaders {
private final Map<String, byte[]> data = new HashMap<>(); protected final Map<String, byte[]> data = new HashMap<>();
@Override @Override
public byte[] put(String key, byte[] value) { public byte[] put(String key, byte[] value) {
@ -18,4 +18,9 @@ public class DefaultTbQueueMsgHeaders implements TbQueueMsgHeaders {
public byte[] get(String key) { public byte[] get(String key) {
return data.get(key); return data.get(key);
} }
@Override
public Map<String, byte[]> getData() {
return data;
}
} }

4
common/queue/src/main/java/org/thingsboard/server/common/TbProtoQueueMsg.java

@ -11,13 +11,13 @@ public class TbProtoQueueMsg<T extends com.google.protobuf.GeneratedMessageV3> i
private final UUID key; private final UUID key;
private final T value; private final T value;
private final DefaultTbQueueMsgHeaders headers; private final TbQueueMsgHeaders headers;
public TbProtoQueueMsg(UUID key, T value) { public TbProtoQueueMsg(UUID key, T value) {
this(key, value, new DefaultTbQueueMsgHeaders()); this(key, value, new DefaultTbQueueMsgHeaders());
} }
public TbProtoQueueMsg(UUID key, T value, DefaultTbQueueMsgHeaders headers) { public TbProtoQueueMsg(UUID key, T value, TbQueueMsgHeaders headers) {
this.key = key; this.key = key;
this.value = value; this.value = value;
this.headers = headers; this.headers = headers;

39
common/queue/src/main/java/org/thingsboard/server/kafka/KafkaTbQueueMsg.java

@ -0,0 +1,39 @@
package org.thingsboard.server.kafka;
import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.thingsboard.server.TbQueueMsg;
import org.thingsboard.server.TbQueueMsgHeaders;
import org.thingsboard.server.common.DefaultTbQueueMsgHeaders;
import java.util.UUID;
public class KafkaTbQueueMsg implements TbQueueMsg {
private final UUID key;
private final TbQueueMsgHeaders headers;
private final byte[] data;
public KafkaTbQueueMsg(ConsumerRecord<String, byte[]> record) {
this.key = UUID.fromString(record.key());
TbQueueMsgHeaders headers = new DefaultTbQueueMsgHeaders();
record.headers().forEach(header -> {
headers.put(header.key(), header.value());
});
this.headers = headers;
this.data = record.value();
}
@Override
public UUID getKey() {
return key;
}
@Override
public TbQueueMsgHeaders getHeaders() {
return headers;
}
@Override
public byte[] getData() {
return data;
}
}

12
common/queue/src/main/java/org/thingsboard/server/kafka/KafkaTbQueueMsgMetadata.java

@ -0,0 +1,12 @@
package org.thingsboard.server.kafka;
import lombok.AllArgsConstructor;
import lombok.Data;
import org.apache.kafka.clients.producer.RecordMetadata;
import org.thingsboard.server.TbQueueMsgMetadata;
@Data
@AllArgsConstructor
public class KafkaTbQueueMsgMetadata implements TbQueueMsgMetadata {
private RecordMetadata metadata;
}

9
common/queue/src/main/java/org/thingsboard/server/kafka/TBKafkaAdmin.java

@ -15,10 +15,12 @@
*/ */
package org.thingsboard.server.kafka; package org.thingsboard.server.kafka;
import com.google.common.util.concurrent.ListenableFuture;
import org.apache.kafka.clients.admin.*; import org.apache.kafka.clients.admin.*;
import org.apache.kafka.clients.consumer.ConsumerRecords; import org.apache.kafka.clients.consumer.ConsumerRecords;
import org.apache.kafka.clients.consumer.KafkaConsumer; import org.apache.kafka.clients.consumer.KafkaConsumer;
import org.apache.kafka.common.KafkaFuture; import org.apache.kafka.common.KafkaFuture;
import org.thingsboard.server.TbQueueAdmin;
import java.time.Duration; import java.time.Duration;
import java.util.Collections; import java.util.Collections;
@ -30,7 +32,7 @@ import java.util.concurrent.TimeoutException;
/** /**
* Created by ashvayka on 24.09.18. * Created by ashvayka on 24.09.18.
*/ */
public class TBKafkaAdmin { public class TBKafkaAdmin implements TbQueueAdmin {
AdminClient client; AdminClient client;
@ -66,4 +68,9 @@ public class TBKafkaAdmin {
} }
} }
@Override
public ListenableFuture<Void> createTopicIfNotExists(String topic) {
return null;
}
} }

48
common/queue/src/main/java/org/thingsboard/server/kafka/TBKafkaConsumerTemplate.java

@ -17,21 +17,27 @@ package org.thingsboard.server.kafka;
import lombok.Builder; import lombok.Builder;
import lombok.Getter; import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.apache.kafka.clients.consumer.ConsumerConfig; import org.apache.kafka.clients.consumer.ConsumerConfig;
import org.apache.kafka.clients.consumer.ConsumerRecord; import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.apache.kafka.clients.consumer.ConsumerRecords; import org.apache.kafka.clients.consumer.ConsumerRecords;
import org.apache.kafka.clients.consumer.KafkaConsumer; import org.apache.kafka.clients.consumer.KafkaConsumer;
import org.thingsboard.server.TbQueueConsumer;
import org.thingsboard.server.TbQueueMsg;
import java.io.IOException; import java.io.IOException;
import java.time.Duration; import java.time.Duration;
import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List;
import java.util.Properties; import java.util.Properties;
import java.util.UUID; import java.util.UUID;
/** /**
* Created by ashvayka on 24.09.18. * Created by ashvayka on 24.09.18.
*/ */
public class TBKafkaConsumerTemplate<T> { @Slf4j
public class TBKafkaConsumerTemplate<T extends TbQueueMsg> implements TbQueueConsumer<T> {
private final KafkaConsumer<String, byte[]> consumer; private final KafkaConsumer<String, byte[]> consumer;
private final TbKafkaDecoder<T> decoder; private final TbKafkaDecoder<T> decoder;
@ -66,23 +72,55 @@ public class TBKafkaConsumerTemplate<T> {
this.topic = topic; this.topic = topic;
} }
@Override
public void subscribe() { public void subscribe() {
consumer.subscribe(Collections.singletonList(topic)); consumer.subscribe(Collections.singletonList(topic));
} }
@Override
public List<T> poll(long durationInMillis) {
ConsumerRecords<String, byte[]> records = consumer.poll(Duration.ofMillis(durationInMillis));
if (records.count() > 0) {
List<T> result = new ArrayList<>();
records.forEach(record -> {
try {
result.add(decode(record));
} catch (IOException e) {
log.error("Failed decode record: [{}]", record);
}
});
return result;
}
return Collections.emptyList();
}
@Override
public void commit() {
consumer.commitAsync();
}
@Override
public void unsubscribe() { public void unsubscribe() {
consumer.unsubscribe(); consumer.unsubscribe();
} }
public ConsumerRecords<String, byte[]> poll(Duration duration) { // public void subscribe() {
return consumer.poll(duration); // consumer.subscribe(Collections.singletonList(topic));
} // }
//
//
// public ConsumerRecords<String, byte[]> poll(Duration duration) {
// return consumer.poll(duration);
// }
public T decode(ConsumerRecord<String, byte[]> record) throws IOException { public T decode(ConsumerRecord<String, byte[]> record) throws IOException {
return decoder.decode(record.value()); return decoder.decode(new KafkaTbQueueMsg(record));
} }
public UUID extractRequestId(T value) { public UUID extractRequestId(T value) {
return requestIdExtractor.extractRequestId(value); return requestIdExtractor.extractRequestId(value);
} }
} }

104
common/queue/src/main/java/org/thingsboard/server/kafka/TBKafkaProducerTemplate.java

@ -15,42 +15,45 @@
*/ */
package org.thingsboard.server.kafka; package org.thingsboard.server.kafka;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.JdkFutureAdapters;
import com.google.common.util.concurrent.ListenableFuture;
import lombok.Builder; import lombok.Builder;
import lombok.Getter; import lombok.Getter;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.kafka.clients.admin.CreateTopicsResult;
import org.apache.kafka.clients.admin.NewTopic;
import org.apache.kafka.clients.admin.TopicDescription;
import org.apache.kafka.clients.producer.Callback;
import org.apache.kafka.clients.producer.KafkaProducer; import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.ProducerConfig; import org.apache.kafka.clients.producer.ProducerConfig;
import org.apache.kafka.clients.producer.ProducerRecord; import org.apache.kafka.clients.producer.ProducerRecord;
import org.apache.kafka.clients.producer.RecordMetadata; import org.apache.kafka.clients.producer.RecordMetadata;
import org.apache.kafka.common.KafkaFuture;
import org.apache.kafka.common.PartitionInfo; import org.apache.kafka.common.PartitionInfo;
import org.apache.kafka.common.errors.TopicExistsException;
import org.apache.kafka.common.header.Header; import org.apache.kafka.common.header.Header;
import org.apache.kafka.common.header.internals.RecordHeader;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import org.thingsboard.server.TbQueueCallback;
import org.thingsboard.server.TbQueueMsg;
import org.thingsboard.server.TbQueueMsgMetadata;
import org.thingsboard.server.TbQueueProducer;
import java.util.List; import java.util.List;
import java.util.Properties; import java.util.Properties;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
/** /**
* Created by ashvayka on 24.09.18. * Created by ashvayka on 24.09.18.
*/ */
@Slf4j @Slf4j
public class TBKafkaProducerTemplate<T> { public class TBKafkaProducerTemplate<T extends TbQueueMsg> implements TbQueueProducer<T> {
private final KafkaProducer<String, byte[]> producer; private final KafkaProducer<String, byte[]> producer;
private final TbKafkaEncoder<T> encoder;
private final TbKafkaPartitioner<T> partitioner; private final TbKafkaPartitioner<T> partitioner;
private ConcurrentMap<String, List<PartitionInfo>> partitionInfoMap; private ConcurrentMap<String, List<PartitionInfo>> partitionInfoMap;
@Getter @Getter
private final String defaultTopic; private final String defaultTopic;
@ -58,8 +61,7 @@ public class TBKafkaProducerTemplate<T> {
private final TbKafkaSettings settings; private final TbKafkaSettings settings;
@Builder @Builder
private TBKafkaProducerTemplate(TbKafkaSettings settings, TbKafkaEncoder<T> encoder, private TBKafkaProducerTemplate(TbKafkaSettings settings, TbKafkaPartitioner<T> partitioner, String defaultTopic, String clientId) {
TbKafkaPartitioner<T> partitioner, String defaultTopic, String clientId) {
Properties props = settings.toProps(); Properties props = settings.toProps();
props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.StringSerializer"); props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.StringSerializer");
props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.ByteArraySerializer"); props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.ByteArraySerializer");
@ -68,7 +70,6 @@ public class TBKafkaProducerTemplate<T> {
} }
this.settings = settings; this.settings = settings;
this.producer = new KafkaProducer<>(props); this.producer = new KafkaProducer<>(props);
this.encoder = encoder;
this.partitioner = partitioner; this.partitioner = partitioner;
this.defaultTopic = defaultTopic; this.defaultTopic = defaultTopic;
} }
@ -89,43 +90,68 @@ public class TBKafkaProducerTemplate<T> {
} }
} }
public Future<RecordMetadata> send(String key, T value, Callback callback) { @Override
return send(key, value, null, callback); public ListenableFuture<TbQueueMsgMetadata> send(T msg, TbQueueCallback callback) {
} return send(defaultTopic, msg, callback);
public Future<RecordMetadata> send(String key, T value, Iterable<Header> headers, Callback callback) {
return send(key, value, null, headers, callback);
} }
public Future<RecordMetadata> send(String key, T value, Long timestamp, Iterable<Header> headers, Callback callback) { @Override
if (!StringUtils.isEmpty(this.defaultTopic)) { public ListenableFuture<TbQueueMsgMetadata> send(String topic, T msg, TbQueueCallback callback) {
return send(this.defaultTopic, key, value, timestamp, headers, callback); String key = msg.getKey().toString();
} else { byte[] data = msg.getData();
throw new RuntimeException("Failed to send message! Default topic is not specified!"); ProducerRecord<String, byte[]> record;
} Iterable<Header> headers = msg.getHeaders().getData().entrySet().stream().map(e -> new RecordHeader(e.getKey(), e.getValue())).collect(Collectors.toList());
}
public Future<RecordMetadata> send(String topic, String key, T value, Iterable<Header> headers, Callback callback) { Integer partition = getPartition(topic, msg);
return send(topic, key, value, null, headers, callback); record = new ProducerRecord<>(topic, partition, key, data, headers);
} Future<RecordMetadata> result = producer.send(record, (metadata, exception) -> {
if (exception == null) {
callback.onSuccess(new KafkaTbQueueMsgMetadata(metadata));
} else {
callback.onFailure(exception);
}
});
public Future<RecordMetadata> send(String topic, String key, T value, Callback callback) { return Futures.transform(JdkFutureAdapters.listenInPoolThread(result), metadata -> new KafkaTbQueueMsgMetadata(metadata));
return send(topic, key, value, null, null, callback);
} }
public Future<RecordMetadata> send(String topic, String key, T value, Long timestamp, Iterable<Header> headers, Callback callback) { // public Future<RecordMetadata> send(String key, T value, Callback callback) {
byte[] data = encoder.encode(value); // return send(key, value, null, callback);
ProducerRecord<String, byte[]> record; // }
Integer partition = getPartition(topic, key, value, data); //
record = new ProducerRecord<>(topic, partition, timestamp, key, data, headers); // public Future<RecordMetadata> send(String key, T value, Iterable<Header> headers, Callback callback) {
return producer.send(record, callback); // return send(key, value, null, headers, callback);
} // }
//
// public Future<RecordMetadata> send(String key, T value, Long timestamp, Iterable<Header> headers, Callback callback) {
// if (!StringUtils.isEmpty(this.defaultTopic)) {
// return send(this.defaultTopic, key, value, timestamp, headers, callback);
// } else {
// throw new RuntimeException("Failed to send message! Default topic is not specified!");
// }
// }
//
// public Future<RecordMetadata> send(String topic, String key, T value, Iterable<Header> headers, Callback callback) {
// return send(topic, key, value, null, headers, callback);
// }
//
// public Future<RecordMetadata> send(String topic, String key, T value, Callback callback) {
// return send(topic, key, value, null, null, callback);
// }
//
// public Future<RecordMetadata> send(String topic, String key, T value, Long timestamp, Iterable<Header> headers, Callback callback) {
// byte[] data = encoder.encode(value);
// ProducerRecord<String, byte[]> record;
// Integer partition = getPartition(topic, key, value, data);
// record = new ProducerRecord<>(topic, partition, timestamp, key, data, headers);
// return producer.send(record, callback);
// }
private Integer getPartition(String topic, String key, T value, byte[] data) { private Integer getPartition(String topic, T value) {
if (partitioner == null) { if (partitioner == null) {
return null; return null;
} else { } else {
return partitioner.partition(topic, key, value, data, partitionInfoMap.computeIfAbsent(topic, producer::partitionsFor)); return partitioner.partition(topic, value.getKey().toString(), value, value.getData(), partitionInfoMap.computeIfAbsent(topic, producer::partitionsFor));
} }
} }
} }

4
common/queue/src/main/java/org/thingsboard/server/kafka/TbKafkaDecoder.java

@ -15,6 +15,8 @@
*/ */
package org.thingsboard.server.kafka; package org.thingsboard.server.kafka;
import org.thingsboard.server.TbQueueMsg;
import java.io.IOException; import java.io.IOException;
/** /**
@ -22,6 +24,6 @@ import java.io.IOException;
*/ */
public interface TbKafkaDecoder<T> { public interface TbKafkaDecoder<T> {
T decode(byte[] data) throws IOException; T decode(TbQueueMsg msg) throws IOException;
} }

45
common/queue/src/main/java/org/thingsboard/server/memory/InMemoryStorage.java

@ -0,0 +1,45 @@
package org.thingsboard.server.memory;
import org.thingsboard.server.TbQueueMsg;
import java.util.LinkedList;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.ConcurrentHashMap;
public final class InMemoryStorage {
private static InMemoryStorage instance;
private final Map<String, Queue<TbQueueMsg>> storage;
private InMemoryStorage() {
storage = new ConcurrentHashMap<>();
}
public static InMemoryStorage getInstance() {
if (instance == null) {
synchronized (InMemoryStorage.class) {
if (instance == null) {
instance = new InMemoryStorage();
}
}
}
return instance;
}
public boolean put(String topic, TbQueueMsg msg) {
return storage.computeIfAbsent(topic, (t) -> new LinkedList<>()).add(msg);
}
public TbQueueMsg get(String topic) {
if (storage.containsKey(topic)) {
return storage.get(topic).peek();
}
return null;
}
public void commit(String topic) {
if (storage.containsKey(topic)) {
storage.get(topic).remove();
}
}
}

42
common/queue/src/main/java/org/thingsboard/server/memory/InMemoryTbQueueConsumer.java

@ -0,0 +1,42 @@
package org.thingsboard.server.memory;
import org.thingsboard.server.TbQueueConsumer;
import org.thingsboard.server.TbQueueMsg;
import java.util.Collections;
import java.util.List;
public class InMemoryTbQueueConsumer<T extends TbQueueMsg> implements TbQueueConsumer<T> {
private final InMemoryStorage storage = InMemoryStorage.getInstance();
public InMemoryTbQueueConsumer(String topic) {
this.topic = topic;
}
private final String topic;
@Override
public String getTopic() {
return topic;
}
@Override
public void subscribe() {
}
@Override
public void unsubscribe() {
}
@Override
public List<T> poll(long durationInMillis) {
return Collections.singletonList((T)storage.get(topic));
}
@Override
public void commit() {
storage.commit(topic);
}
}

43
common/queue/src/main/java/org/thingsboard/server/memory/InMemoryTbQueueProducer.java

@ -0,0 +1,43 @@
package org.thingsboard.server.memory;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import org.thingsboard.server.TbQueueCallback;
import org.thingsboard.server.TbQueueMsg;
import org.thingsboard.server.TbQueueMsgMetadata;
import org.thingsboard.server.TbQueueProducer;
public class InMemoryTbQueueProducer<T extends TbQueueMsg> implements TbQueueProducer<T> {
private final InMemoryStorage storage = InMemoryStorage.getInstance();
private String defaultTopic;
@Override
public void init() {
}
@Override
public String getDefaultTopic() {
return defaultTopic;
}
@Override
public ListenableFuture<TbQueueMsgMetadata> send(T msg, TbQueueCallback callback) {
return send(defaultTopic, msg, callback);
}
@Override
public ListenableFuture<TbQueueMsgMetadata> send(String topic, T msg, TbQueueCallback callback) {
boolean result = storage.put(topic, msg);
if (result) {
callback.onSuccess(null);
return Futures.immediateCheckedFuture(null);
} else {
Exception e = new RuntimeException("Failure add msg to InMemoryQueue");
callback.onFailure(e);
return Futures.immediateFailedFuture(e);
}
}
}

2
common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java

@ -40,7 +40,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg;
import org.thingsboard.server.gen.transport.TransportProtos.TransportApiRequestMsg; import org.thingsboard.server.gen.transport.TransportProtos.TransportApiRequestMsg;
import org.thingsboard.server.gen.transport.TransportProtos.TransportApiResponseMsg; import org.thingsboard.server.gen.transport.TransportProtos.TransportApiResponseMsg;
import org.thingsboard.server.kafka.AsyncCallbackTemplate; import org.thingsboard.server.common.AsyncCallbackTemplate;
import javax.annotation.PostConstruct; import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy; import javax.annotation.PreDestroy;

6
common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/ToTransportMsgResponseDecoder.java

@ -15,6 +15,7 @@
*/ */
package org.thingsboard.server.common.transport.service; package org.thingsboard.server.common.transport.service;
import org.thingsboard.server.TbQueueMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg;
import org.thingsboard.server.kafka.TbKafkaDecoder; import org.thingsboard.server.kafka.TbKafkaDecoder;
@ -24,8 +25,9 @@ import java.io.IOException;
* Created by ashvayka on 05.10.18. * Created by ashvayka on 05.10.18.
*/ */
public class ToTransportMsgResponseDecoder implements TbKafkaDecoder<ToTransportMsg> { public class ToTransportMsgResponseDecoder implements TbKafkaDecoder<ToTransportMsg> {
@Override @Override
public ToTransportMsg decode(byte[] data) throws IOException { public ToTransportMsg decode(TbQueueMsg msg) throws IOException {
return ToTransportMsg.parseFrom(data); return ToTransportMsg.parseFrom(msg.getData());
} }
} }

6
common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/TransportApiResponseDecoder.java

@ -15,6 +15,7 @@
*/ */
package org.thingsboard.server.common.transport.service; package org.thingsboard.server.common.transport.service;
import org.thingsboard.server.TbQueueMsg;
import org.thingsboard.server.gen.transport.TransportProtos.TransportApiResponseMsg; import org.thingsboard.server.gen.transport.TransportProtos.TransportApiResponseMsg;
import org.thingsboard.server.kafka.TbKafkaDecoder; import org.thingsboard.server.kafka.TbKafkaDecoder;
@ -24,8 +25,9 @@ import java.io.IOException;
* Created by ashvayka on 05.10.18. * Created by ashvayka on 05.10.18.
*/ */
public class TransportApiResponseDecoder implements TbKafkaDecoder<TransportApiResponseMsg> { public class TransportApiResponseDecoder implements TbKafkaDecoder<TransportApiResponseMsg> {
@Override @Override
public TransportApiResponseMsg decode(byte[] data) throws IOException { public TransportApiResponseMsg decode(TbQueueMsg msg) throws IOException {
return TransportApiResponseMsg.parseFrom(data); return TransportApiResponseMsg.parseFrom(msg.getData());
} }
} }

13
dao/src/main/java/org/thingsboard/server/dao/entity/BaseEntityService.java

@ -18,12 +18,21 @@ package org.thingsboard.server.dao.entity;
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.HasName; import org.thingsboard.server.common.data.HasName;
import org.thingsboard.server.common.data.alarm.AlarmId; import org.thingsboard.server.common.data.alarm.AlarmId;
import org.thingsboard.server.common.data.id.*; import org.thingsboard.server.common.data.id.AssetId;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.DashboardId;
import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.EntityViewId;
import org.thingsboard.server.common.data.id.RuleChainId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.UserId;
import org.thingsboard.server.dao.alarm.AlarmService; import org.thingsboard.server.dao.alarm.AlarmService;
import org.thingsboard.server.dao.asset.AssetService; import org.thingsboard.server.dao.asset.AssetService;
import org.thingsboard.server.dao.customer.CustomerService; import org.thingsboard.server.dao.customer.CustomerService;
@ -109,7 +118,7 @@ public class BaseEntityService extends AbstractEntityService implements EntitySe
default: default:
throw new IllegalStateException("Not Implemented!"); throw new IllegalStateException("Not Implemented!");
} }
entityName = Futures.transform(hasName, (Function<HasName, String>) hasName1 -> hasName1 != null ? hasName1.getName() : null ); entityName = Futures.transform(hasName, (Function<HasName, String>) hasName1 -> hasName1 != null ? hasName1.getName() : null, MoreExecutors.directExecutor());
return entityName; return entityName;
} }

38
dao/src/main/java/org/thingsboard/server/dao/relation/BaseRelationService.java

@ -16,7 +16,10 @@
package org.thingsboard.server.dao.relation; package org.thingsboard.server.dao.relation;
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.util.concurrent.*; import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.Cache; import org.springframework.cache.Cache;
@ -206,17 +209,20 @@ public class BaseRelationService implements RelationService {
relations -> { relations -> {
List<ListenableFuture<Boolean>> results = deleteRelationGroupsAsync(tenantId, relations, cache, true); List<ListenableFuture<Boolean>> results = deleteRelationGroupsAsync(tenantId, relations, cache, true);
return Futures.allAsList(results); return Futures.allAsList(results);
}); }, MoreExecutors.directExecutor());
ListenableFuture<List<Boolean>> outboundDeletions = Futures.transformAsync(outboundRelations, ListenableFuture<List<Boolean>> outboundDeletions = Futures.transformAsync(outboundRelations,
relations -> { relations -> {
List<ListenableFuture<Boolean>> results = deleteRelationGroupsAsync(tenantId, relations, cache, false); List<ListenableFuture<Boolean>> results = deleteRelationGroupsAsync(tenantId, relations, cache, false);
return Futures.allAsList(results); return Futures.allAsList(results);
}); }, MoreExecutors.directExecutor());
ListenableFuture<List<List<Boolean>>> deletionsFuture = Futures.allAsList(inboundDeletions, outboundDeletions); ListenableFuture<List<List<Boolean>>> deletionsFuture = Futures.allAsList(inboundDeletions, outboundDeletions);
return Futures.transform(Futures.transformAsync(deletionsFuture, (deletions) -> relationDao.deleteOutboundRelationsAsync(tenantId, entityId)), result -> null); return Futures.transform(Futures.transformAsync(deletionsFuture,
(deletions) -> relationDao.deleteOutboundRelationsAsync(tenantId, entityId),
MoreExecutors.directExecutor()),
result -> null, MoreExecutors.directExecutor());
} }
private List<ListenableFuture<Boolean>> deleteRelationGroupsAsync(TenantId tenantId, List<List<EntityRelation>> relations, Cache cache, boolean deleteFromDb) { private List<ListenableFuture<Boolean>> deleteRelationGroupsAsync(TenantId tenantId, List<List<EntityRelation>> relations, Cache cache, boolean deleteFromDb) {
@ -306,9 +312,11 @@ public class BaseRelationService implements RelationService {
public void onSuccess(@Nullable List<EntityRelation> result) { public void onSuccess(@Nullable List<EntityRelation> result) {
cache.putIfAbsent(fromAndTypeGroup, result); cache.putIfAbsent(fromAndTypeGroup, result);
} }
@Override @Override
public void onFailure(Throwable t) {} public void onFailure(Throwable t) {
}); }
}, MoreExecutors.directExecutor());
return relationsFuture; return relationsFuture;
} }
} }
@ -328,7 +336,7 @@ public class BaseRelationService implements RelationService {
EntityRelationInfo::setToName)) EntityRelationInfo::setToName))
); );
return Futures.successfulAsList(futures); return Futures.successfulAsList(futures);
}); }, MoreExecutors.directExecutor());
} }
@Cacheable(cacheNames = RELATIONS_CACHE, key = "{#from, #relationType, #typeGroup, 'FROM'}") @Cacheable(cacheNames = RELATIONS_CACHE, key = "{#from, #relationType, #typeGroup, 'FROM'}")
@ -385,9 +393,11 @@ public class BaseRelationService implements RelationService {
public void onSuccess(@Nullable List<EntityRelation> result) { public void onSuccess(@Nullable List<EntityRelation> result) {
cache.putIfAbsent(toAndTypeGroup, result); cache.putIfAbsent(toAndTypeGroup, result);
} }
@Override @Override
public void onFailure(Throwable t) {} public void onFailure(Throwable t) {
}); }
}, MoreExecutors.directExecutor());
return relationsFuture; return relationsFuture;
} }
} }
@ -407,7 +417,7 @@ public class BaseRelationService implements RelationService {
EntityRelationInfo::setFromName)) EntityRelationInfo::setFromName))
); );
return Futures.successfulAsList(futures); return Futures.successfulAsList(futures);
}); }, MoreExecutors.directExecutor());
} }
private ListenableFuture<EntityRelationInfo> fetchRelationInfoAsync(TenantId tenantId, EntityRelation relation, private ListenableFuture<EntityRelationInfo> fetchRelationInfoAsync(TenantId tenantId, EntityRelation relation,
@ -418,7 +428,7 @@ public class BaseRelationService implements RelationService {
EntityRelationInfo entityRelationInfo1 = new EntityRelationInfo(relation); EntityRelationInfo entityRelationInfo1 = new EntityRelationInfo(relation);
entityNameSetter.accept(entityRelationInfo1, entityName1); entityNameSetter.accept(entityRelationInfo1, entityName1);
return entityRelationInfo1; return entityRelationInfo1;
}); }, MoreExecutors.directExecutor());
} }
@Cacheable(cacheNames = RELATIONS_CACHE, key = "{#to, #relationType, #typeGroup, 'TO'}") @Cacheable(cacheNames = RELATIONS_CACHE, key = "{#to, #relationType, #typeGroup, 'TO'}")
@ -466,7 +476,7 @@ public class BaseRelationService implements RelationService {
} }
} }
return relations; return relations;
}); }, MoreExecutors.directExecutor());
} catch (Exception e) { } catch (Exception e) {
log.warn("Failed to query relations: [{}]", query, e); log.warn("Failed to query relations: [{}]", query, e);
throw new RuntimeException(e); throw new RuntimeException(e);
@ -493,7 +503,7 @@ public class BaseRelationService implements RelationService {
})) }))
); );
return Futures.successfulAsList(futures); return Futures.successfulAsList(futures);
}); }, MoreExecutors.directExecutor());
} }
protected void validate(EntityRelation relation) { protected void validate(EntityRelation relation) {
@ -600,7 +610,7 @@ public class BaseRelationService implements RelationService {
} }
//TODO: try to remove this blocking operation //TODO: try to remove this blocking operation
List<Set<EntityRelation>> relations = Futures.successfulAsList(futures).get(); List<Set<EntityRelation>> relations = Futures.successfulAsList(futures).get();
if (fetchLastLevelOnly && lvl > 0){ if (fetchLastLevelOnly && lvl > 0) {
children.clear(); children.clear();
} }
relations.forEach(r -> r.forEach(children::add)); relations.forEach(r -> r.forEach(children::add));

3
dao/src/main/java/org/thingsboard/server/dao/sqlts/timescale/TimescaleTimeseriesDao.java

@ -17,6 +17,7 @@ package org.thingsboard.server.dao.sqlts.timescale;
import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors;
import com.google.common.util.concurrent.SettableFuture; import com.google.common.util.concurrent.SettableFuture;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -143,7 +144,7 @@ public class TimescaleTimeseriesDao extends AbstractSqlTimeseriesDao implements
} else { } else {
return Collections.emptyList(); return Collections.emptyList();
} }
}); }, MoreExecutors.directExecutor());
} }
@Override @Override

5
dao/src/main/java/org/thingsboard/server/dao/timeseries/CassandraBaseTimeseriesDao.java

@ -28,6 +28,7 @@ import com.google.common.util.concurrent.AsyncFunction;
import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -330,7 +331,7 @@ public class CassandraBaseTimeseriesDao extends CassandraAbstractAsyncDao implem
stmt.setInt(6, (int) ttl); stmt.setInt(6, (int) ttl);
} }
futures.add(getFuture(executeAsyncWrite(tenantId, stmt), rs -> null)); futures.add(getFuture(executeAsyncWrite(tenantId, stmt), rs -> null));
return Futures.transform(Futures.allAsList(futures), result -> null); return Futures.transform(Futures.allAsList(futures), result -> null, MoreExecutors.directExecutor());
} }
private void processSetNullValues(TenantId tenantId, EntityId entityId, TsKvEntry tsKvEntry, long ttl, List<ListenableFuture<Void>> futures, long partition, DataType type) { private void processSetNullValues(TenantId tenantId, EntityId entityId, TsKvEntry tsKvEntry, long ttl, List<ListenableFuture<Void>> futures, long partition, DataType type) {
@ -545,7 +546,7 @@ public class CassandraBaseTimeseriesDao extends CassandraAbstractAsyncDao implem
public void onFailure(Throwable t) { public void onFailure(Throwable t) {
log.warn("[{}] Failed to process remove of the latest value", entityId, t); log.warn("[{}] Failed to process remove of the latest value", entityId, t);
} }
}); }, MoreExecutors.directExecutor());
return resultFuture; return resultFuture;
} }

Loading…
Cancel
Save