Browse Source

Created kafka and in-memory queue providers

* Created kafka and in-memory queue providers

* Added header requestTime

* refactored
pull/2566/head
Yevhen Bondarenko 6 years ago
committed by GitHub
parent
commit
dc6081d820
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      application/src/main/java/org/thingsboard/server/actors/service/ActorService.java
  2. 15
      application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java
  3. 15
      application/src/main/java/org/thingsboard/server/service/queue/DefaultTbRuleEngineConsumerService.java
  4. 15
      application/src/main/java/org/thingsboard/server/service/queue/MsgPackCallback.java
  5. 15
      application/src/main/java/org/thingsboard/server/service/queue/TbCoreConsumerService.java
  6. 2
      application/src/main/java/org/thingsboard/server/service/queue/TbCoreConsumerStats.java
  7. 15
      application/src/main/java/org/thingsboard/server/service/queue/TbMsgCallback.java
  8. 15
      application/src/main/java/org/thingsboard/server/service/queue/TbRuleEngineConsumerService.java
  9. 24
      application/src/main/java/org/thingsboard/server/service/queue/TbRuleEngineConsumerStats.java
  10. 8
      application/src/main/java/org/thingsboard/server/service/script/RemoteJsInvokeService.java
  11. 19
      application/src/main/java/org/thingsboard/server/service/transport/DefaultTbCoreToTransportService.java
  12. 37
      application/src/main/java/org/thingsboard/server/service/transport/RemoteRuleEngineTransportService.java
  13. 2
      application/src/main/java/org/thingsboard/server/service/transport/RemoteTransportApiService.java
  14. 15
      application/src/main/java/org/thingsboard/server/service/transport/TbCoreToTransportService.java
  15. 15
      common/queue/src/main/java/org/thingsboard/server/TbQueueAdmin.java
  16. 15
      common/queue/src/main/java/org/thingsboard/server/TbQueueCallback.java
  17. 15
      common/queue/src/main/java/org/thingsboard/server/TbQueueConsumer.java
  18. 15
      common/queue/src/main/java/org/thingsboard/server/TbQueueCoreSettings.java
  19. 15
      common/queue/src/main/java/org/thingsboard/server/TbQueueMsg.java
  20. 15
      common/queue/src/main/java/org/thingsboard/server/TbQueueMsgHeaders.java
  21. 15
      common/queue/src/main/java/org/thingsboard/server/TbQueueMsgMetadata.java
  22. 21
      common/queue/src/main/java/org/thingsboard/server/TbQueueProducer.java
  23. 15
      common/queue/src/main/java/org/thingsboard/server/TbQueueRequestTemplate.java
  24. 15
      common/queue/src/main/java/org/thingsboard/server/TbQueueResponseTemplate.java
  25. 40
      common/queue/src/main/java/org/thingsboard/server/TbQueueTransportApiSettings.java
  26. 29
      common/queue/src/main/java/org/thingsboard/server/common/AbstractTbQueueTemplate.java
  27. 15
      common/queue/src/main/java/org/thingsboard/server/common/DefaultTbQueueMsgHeaders.java
  28. 18
      common/queue/src/main/java/org/thingsboard/server/common/DefaultTbQueueRequestTemplate.java
  29. 88
      common/queue/src/main/java/org/thingsboard/server/common/DefaultTbQueueResponseTemplate.java
  30. 15
      common/queue/src/main/java/org/thingsboard/server/common/TbProtoQueueMsg.java
  31. 50
      common/queue/src/main/java/org/thingsboard/server/kafka/AbstractTbKafkaTemplate.java
  32. 66
      common/queue/src/main/java/org/thingsboard/server/kafka/AsyncCallbackTemplate.java
  33. 15
      common/queue/src/main/java/org/thingsboard/server/kafka/KafkaTbQueueMsg.java
  34. 15
      common/queue/src/main/java/org/thingsboard/server/kafka/KafkaTbQueueMsgMetadata.java
  35. 32
      common/queue/src/main/java/org/thingsboard/server/kafka/TBKafkaAdmin.java
  36. 20
      common/queue/src/main/java/org/thingsboard/server/kafka/TBKafkaConsumerTemplate.java
  37. 44
      common/queue/src/main/java/org/thingsboard/server/kafka/TBKafkaProducerTemplate.java
  38. 213
      common/queue/src/main/java/org/thingsboard/server/kafka/TbKafkaRequestTemplate.java
  39. 161
      common/queue/src/main/java/org/thingsboard/server/kafka/TbKafkaResponseTemplate.java
  40. 12
      common/queue/src/main/java/org/thingsboard/server/kafka/TbKafkaSettings.java
  41. 15
      common/queue/src/main/java/org/thingsboard/server/memory/InMemoryStorage.java
  42. 15
      common/queue/src/main/java/org/thingsboard/server/memory/InMemoryTbQueueConsumer.java
  43. 30
      common/queue/src/main/java/org/thingsboard/server/memory/InMemoryTbQueueProducer.java
  44. 79
      common/queue/src/main/java/org/thingsboard/server/provider/InMemoryTbCoreQueueProvider.java
  45. 79
      common/queue/src/main/java/org/thingsboard/server/provider/InMemoryTransportQueueProvider.java
  46. 88
      common/queue/src/main/java/org/thingsboard/server/provider/KafkaTbCoreQueueProvider.java
  47. 70
      common/queue/src/main/java/org/thingsboard/server/provider/KafkaTransportQueueProvider.java
  48. 17
      common/queue/src/main/java/org/thingsboard/server/provider/TbCoreQueueProvider.java
  49. 15
      common/queue/src/main/java/org/thingsboard/server/provider/TransportQueueProvider.java
  50. 2
      common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java

1
application/src/main/java/org/thingsboard/server/actors/service/ActorService.java

@ -20,7 +20,6 @@ import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
import org.thingsboard.server.common.msg.cluster.SendToClusterMsg;
import org.thingsboard.server.common.msg.system.ServiceToRuleEngineMsg;
import org.thingsboard.server.common.transport.SessionMsgProcessor;
import org.thingsboard.server.service.cluster.discovery.DiscoveryServiceListener;
import org.thingsboard.server.service.cluster.rpc.RpcMsgListener;

15
application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java

@ -1,3 +1,18 @@
/**
* 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 akka.actor.ActorRef;

15
application/src/main/java/org/thingsboard/server/service/queue/DefaultTbRuleEngineConsumerService.java

@ -1,3 +1,18 @@
/**
* 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 akka.actor.ActorRef;

15
application/src/main/java/org/thingsboard/server/service/queue/MsgPackCallback.java

@ -1,3 +1,18 @@
/**
* 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;

15
application/src/main/java/org/thingsboard/server/service/queue/TbCoreConsumerService.java

@ -1,3 +1,18 @@
/**
* 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 org.thingsboard.server.gen.transport.TransportProtos;

2
application/src/main/java/org/thingsboard/server/service/queue/TbCoreConsumerStats.java

@ -5,7 +5,7 @@
* 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
* 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,

15
application/src/main/java/org/thingsboard/server/service/queue/TbMsgCallback.java

@ -1,3 +1,18 @@
/**
* 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;
public interface TbMsgCallback {

15
application/src/main/java/org/thingsboard/server/service/queue/TbRuleEngineConsumerService.java

@ -1,3 +1,18 @@
/**
* 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;
public interface TbRuleEngineConsumerService {

24
application/src/main/java/org/thingsboard/server/service/queue/TbRuleEngineConsumerStats.java

@ -25,13 +25,13 @@ public class TbRuleEngineConsumerStats {
private final AtomicInteger totalCounter = new AtomicInteger(0);
private final AtomicInteger sessionEventCounter = new AtomicInteger(0);
private final AtomicInteger postTelemetryCounter = new AtomicInteger(0);
private final AtomicInteger postAttributesCounter = new AtomicInteger(0);
// private final AtomicInteger postTelemetryCounter = new AtomicInteger(0);
// private final AtomicInteger postAttributesCounter = 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 toServerRPCCallRequestCounter = new AtomicInteger(0);
// private final AtomicInteger toServerRPCCallRequestCounter = new AtomicInteger(0);
private final AtomicInteger subscriptionInfoCounter = new AtomicInteger(0);
private final AtomicInteger claimDeviceCounter = new AtomicInteger(0);
@ -40,12 +40,12 @@ public class TbRuleEngineConsumerStats {
if (msg.hasSessionEvent()) {
sessionEventCounter.incrementAndGet();
}
if (msg.hasPostTelemetry()) {
postTelemetryCounter.incrementAndGet();
}
if (msg.hasPostAttributes()) {
postAttributesCounter.incrementAndGet();
}
// if (msg.hasPostTelemetry()) {
// postTelemetryCounter.incrementAndGet();
// }
// if (msg.hasPostAttributes()) {
// postAttributesCounter.incrementAndGet();
// }
if (msg.hasGetAttributes()) {
getAttributesCounter.incrementAndGet();
}
@ -58,9 +58,9 @@ public class TbRuleEngineConsumerStats {
if (msg.hasToDeviceRPCCallResponse()) {
toDeviceRPCCallResponseCounter.incrementAndGet();
}
if (msg.hasToServerRPCCallRequest()) {
toServerRPCCallRequestCounter.incrementAndGet();
}
// if (msg.hasToServerRPCCallRequest()) {
// toServerRPCCallRequestCounter.incrementAndGet();
// }
if (msg.hasSubscriptionInfo()) {
subscriptionInfoCounter.incrementAndGet();
}

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

@ -20,7 +20,6 @@ import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.scheduling.annotation.Scheduled;
@ -29,7 +28,6 @@ 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.kafka.TbNodeIdProvider;
import javax.annotation.Nullable;
import javax.annotation.PostConstruct;
@ -45,12 +43,6 @@ import java.util.concurrent.atomic.AtomicInteger;
@Service
public class RemoteJsInvokeService extends AbstractJsInvokeService {
@Autowired
private TbNodeIdProvider nodeIdProvider;
@Autowired
private TbKafkaSettings kafkaSettings;
@Value("${js.remote.request_topic}")
private String requestTopic;

19
application/src/main/java/org/thingsboard/server/service/transport/DefaultTbCoreToTransportService.java

@ -1,3 +1,18 @@
/**
* 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.transport;
import lombok.extern.slf4j.Slf4j;
@ -15,6 +30,8 @@ import org.thingsboard.server.provider.TbCoreQueueProvider;
import java.util.UUID;
import java.util.function.Consumer;
import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID;
@Slf4j
@Service
@ConditionalOnExpression("'${service.type:null}'=='monolith' || '${service.type:null}'=='tb-core')")
@ -42,7 +59,7 @@ public class DefaultTbCoreToTransportService implements TbCoreToTransportService
UUID sessionId = new UUID(msg.getSessionIdMSB(), msg.getSessionIdLSB());
ToTransportMsg transportMsg = ToTransportMsg.newBuilder().setToDeviceSessionMsg(msg).build();
log.trace("[{}][{}] Pushing session data to topic: {}", topic, sessionId, transportMsg);
TbProtoQueueMsg<ToTransportMsg> queueMsg = new TbProtoQueueMsg<>(sessionId, transportMsg);
TbProtoQueueMsg<ToTransportMsg> queueMsg = new TbProtoQueueMsg<>(NULL_UUID, transportMsg);
tbTransportProducer.send(topic, queueMsg, new QueueCallbackAdaptor(onSuccess, onFailure));
}

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

@ -41,9 +41,8 @@ import org.thingsboard.server.gen.transport.TransportProtos.DeviceActorToTranspo
import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg;
import org.thingsboard.server.gen.transport.TransportProtos.TransportToDeviceActorMsg;
import org.thingsboard.server.kafka.TbNodeIdProvider;
import org.thingsboard.server.provider.TbCoreQueueProvider;
import org.thingsboard.server.service.cluster.routing.ClusterRoutingService;
import org.thingsboard.server.service.cluster.rpc.ClusterRpcService;
import org.thingsboard.server.service.encoding.DataDecodingEncodingService;
import org.thingsboard.server.service.queue.TbCoreConsumerStats;
import org.thingsboard.server.service.transport.msg.TransportToDeviceActorMsgWrapper;
@ -65,7 +64,7 @@ import java.util.function.Consumer;
@Slf4j
@Service
@ConditionalOnProperty(prefix = "transport", value = "type", havingValue = "remote")
public class RemoteRuleEngineTransportService implements RuleEngineTransportService {
public class RemoteRuleEngineTransportService {
@Value("${transport.remote.rule_engine.topic}")
private String ruleEngineTopic;
@ -85,12 +84,6 @@ public class RemoteRuleEngineTransportService implements RuleEngineTransportServ
@Value("${transport.remote.rule_engine.stats.enabled:false}")
private boolean statsEnabled;
// @Autowired
// private TbKafkaSettings kafkaSettings;
//
@Autowired
private TbNodeIdProvider nodeIdProvider;
@Autowired
private ActorSystemContext actorContext;
@ -102,6 +95,9 @@ public class RemoteRuleEngineTransportService implements RuleEngineTransportServ
@Autowired
private DataDecodingEncodingService encodingService;
@Autowired
private TbCoreQueueProvider coreQueueProvider;
private TbQueueConsumer<TbProtoQueueMsg<ToRuleEngineMsg>> ruleEngineConsumer;
private TbQueueProducer<TbProtoQueueMsg<ToTransportMsg>> notificationsProducer;
@ -114,26 +110,12 @@ public class RemoteRuleEngineTransportService implements RuleEngineTransportServ
@PostConstruct
public void init() {
TBKafkaProducerTemplate.TBKafkaProducerTemplateBuilder<ToTransportMsg> notificationsProducerBuilder = TBKafkaProducerTemplate.builder();
notificationsProducerBuilder.settings(kafkaSettings);
notificationsProducerBuilder.clientId("producer-transport-notification-" + nodeIdProvider.getNodeId());
notificationsProducerBuilder.encoder(new ToTransportMsgEncoder());
notificationsProducer = notificationsProducerBuilder.build();
notificationsProducer = coreQueueProvider.getTransportMsgProducer();
notificationsProducer.init();
TBKafkaConsumerTemplate.TBKafkaConsumerTemplateBuilder<ToRuleEngineMsg> ruleEngineConsumerBuilder = TBKafkaConsumerTemplate.builder();
ruleEngineConsumerBuilder.settings(kafkaSettings);
ruleEngineConsumerBuilder.topic(ruleEngineTopic);
ruleEngineConsumerBuilder.clientId("transport-" + nodeIdProvider.getNodeId());
ruleEngineConsumerBuilder.groupId("tb-node");
ruleEngineConsumerBuilder.autoCommit(true);
ruleEngineConsumerBuilder.autoCommitIntervalMs(autoCommitInterval);
ruleEngineConsumerBuilder.maxPollRecords(pollRecordsPackSize);
ruleEngineConsumerBuilder.decoder(new ToRuleEngineMsgDecoder());
ruleEngineConsumer = ruleEngineConsumerBuilder.build();
ruleEngineConsumer.subscribe();
//TODO: 2.5
// ruleEngineConsumer =
// ruleEngineConsumer.subscribe();
}
@EventListener(ApplicationReadyEvent.class)
@ -198,6 +180,7 @@ public class RemoteRuleEngineTransportService implements RuleEngineTransportServ
UUID sessionId = new UUID(msg.getSessionIdMSB(), msg.getSessionIdLSB());
ToTransportMsg transportMsg = ToTransportMsg.newBuilder().setToDeviceSessionMsg(msg).build();
log.trace("[{}][{}] Pushing session data to topic: {}", topic, sessionId, transportMsg);
//TODO: 2.5 id
TbProtoQueueMsg<ToTransportMsg> queueMsg = new TbProtoQueueMsg<>(sessionId, transportMsg);
notificationsProducer.send(topic, queueMsg, new QueueCallbackAdaptor(onSuccess, onFailure));
}

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

@ -5,7 +5,7 @@
* 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
* 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,

15
application/src/main/java/org/thingsboard/server/service/transport/TbCoreToTransportService.java

@ -1,3 +1,18 @@
/**
* 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.transport;
import org.thingsboard.server.gen.transport.TransportProtos;

15
common/queue/src/main/java/org/thingsboard/server/TbQueueAdmin.java

@ -1,3 +1,18 @@
/**
* 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;
import com.google.common.util.concurrent.ListenableFuture;

15
common/queue/src/main/java/org/thingsboard/server/TbQueueCallback.java

@ -1,3 +1,18 @@
/**
* 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;
public interface TbQueueCallback {

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

@ -1,3 +1,18 @@
/**
* 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;
import java.util.List;

15
common/queue/src/main/java/org/thingsboard/server/kafka/TbKafkaRequestIdExtractor.java → common/queue/src/main/java/org/thingsboard/server/TbQueueCoreSettings.java

@ -13,12 +13,19 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.kafka;
package org.thingsboard.server;
import java.util.UUID;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
public interface TbKafkaRequestIdExtractor<T> {
@Data
@Component
public class TbQueueCoreSettings {
UUID extractRequestId(T value);
@Value("${queue.core.topic}")
private String topic;
@Value("${queue.core.partitions}")
private int partitions;
}

15
common/queue/src/main/java/org/thingsboard/server/TbQueueMsg.java

@ -1,3 +1,18 @@
/**
* 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;
import java.util.UUID;

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

@ -1,3 +1,18 @@
/**
* 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;
import java.util.Map;

15
common/queue/src/main/java/org/thingsboard/server/TbQueueMsgMetadata.java

@ -1,3 +1,18 @@
/**
* 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;
public interface TbQueueMsgMetadata {

21
common/queue/src/main/java/org/thingsboard/server/TbQueueProducer.java

@ -1,15 +1,28 @@
/**
* 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;
import com.google.common.util.concurrent.ListenableFuture;
public interface TbQueueProducer<T extends TbQueueMsg> {
void init();
String getDefaultTopic();
ListenableFuture<TbQueueMsgMetadata> send(T msg, TbQueueCallback callback);
void send(T msg, TbQueueCallback callback);
ListenableFuture<TbQueueMsgMetadata> send(String topic, T msg, TbQueueCallback callback);
void send(String topic, T msg, TbQueueCallback callback);
}

15
common/queue/src/main/java/org/thingsboard/server/TbQueueRequestTemplate.java

@ -1,3 +1,18 @@
/**
* 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;
import com.google.common.util.concurrent.ListenableFuture;

15
common/queue/src/main/java/org/thingsboard/server/TbQueueResponseTemplate.java

@ -1,3 +1,18 @@
/**
* 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;
public interface TbQueueResponseTemplate<Request extends TbQueueMsg, Response extends TbQueueMsg> {

40
common/queue/src/main/java/org/thingsboard/server/TbQueueTransportApiSettings.java

@ -0,0 +1,40 @@
/**
* 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;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Data
@Component
public class TbQueueTransportApiSettings {
@Value("${queue.transport_api.requests_topic}")
private String requestsTopic;
@Value("${queue.transport_api.responses_topic}")
private String responsesTopic;
@Value("${queue.transport_api.max_pending_requests}")
private int maxPendingRequests;
@Value("${queue.transport_api.max_requests_timeout}")
private int maxRequestsTimeout;
@Value("${queue.transport_api.response_poll_interval}")
private long responsePollInterval;
}

29
common/queue/src/main/java/org/thingsboard/server/common/AbstractTbQueueTemplate.java

@ -1,3 +1,18 @@
/**
* Copyright © 2016-2020 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.common;
import java.nio.ByteBuffer;
@ -7,6 +22,7 @@ import java.util.UUID;
public class AbstractTbQueueTemplate {
protected static final String REQUEST_ID_HEADER = "requestId";
protected static final String RESPONSE_TOPIC_HEADER = "responseTopic";
protected static final String REQUEST_TIME = "requestTime";
protected byte[] uuidToBytes(UUID uuid) {
ByteBuffer buf = ByteBuffer.allocate(16);
@ -29,4 +45,17 @@ public class AbstractTbQueueTemplate {
protected String bytesToString(byte[] data) {
return new String(data, StandardCharsets.UTF_8);
}
private static ByteBuffer longBuffer = ByteBuffer.allocate(Long.BYTES);
protected static byte[] longToBytes(long x) {
longBuffer.putLong(0, x);
return longBuffer.array();
}
protected static long bytesToLong(byte[] bytes) {
longBuffer.put(bytes, 0, bytes.length);
longBuffer.flip();//need flip
return longBuffer.getLong();
}
}

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

@ -1,3 +1,18 @@
/**
* Copyright © 2016-2020 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.common;
import org.thingsboard.server.TbQueueMsgHeaders;

18
common/queue/src/main/java/org/thingsboard/server/common/DefaultTbQueueRequestTemplate.java

@ -1,3 +1,18 @@
/**
* Copyright © 2016-2020 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.common;
import com.google.common.util.concurrent.Futures;
@ -79,7 +94,7 @@ public class DefaultTbQueueRequestTemplate<Request extends TbQueueMsg, Response
responses.forEach(response -> {
log.trace("Received response to Kafka Template request: {}", response);
byte[] requestIdHeader = response.getHeaders().get(REQUEST_ID_HEADER);
UUID requestId = null;
UUID requestId;
if (requestIdHeader == null) {
log.error("[{}] Missing requestId in header and body", response);
} else {
@ -140,6 +155,7 @@ public class DefaultTbQueueRequestTemplate<Request extends TbQueueMsg, Response
UUID requestId = UUID.randomUUID();
request.getHeaders().put(REQUEST_ID_HEADER, uuidToBytes(requestId));
request.getHeaders().put(RESPONSE_TOPIC_HEADER, stringToBytes(responseTemplate.getTopic()));
request.getHeaders().put(REQUEST_TIME, longToBytes(System.currentTimeMillis()));
SettableFuture<Response> future = SettableFuture.create();
ResponseMetaData<Response> responseMetaData = new ResponseMetaData<>(tickTs + maxRequestTimeout, future);
pendingRequests.putIfAbsent(requestId, responseMetaData);

88
common/queue/src/main/java/org/thingsboard/server/common/DefaultTbQueueResponseTemplate.java

@ -1,3 +1,18 @@
/**
* Copyright © 2016-2020 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.common;
import lombok.Builder;
@ -70,41 +85,46 @@ public class DefaultTbQueueResponseTemplate<Request extends TbQueueMsg, Response
}
}
List<Request> requests = requestTemplate.poll(pollInterval);
requests.forEach(request -> {
byte[] requestIdHeader = request.getHeaders().get(REQUEST_ID_HEADER);
if (requestIdHeader == null) {
log.error("[{}] Missing requestId in header", request);
return;
}
byte[] responseTopicHeader = request.getHeaders().get(RESPONSE_TOPIC_HEADER);
if (responseTopicHeader == null) {
log.error("[{}] Missing response topic in header", request);
return;
}
UUID requestId = bytesToUuid(requestIdHeader);
String responseTopic = bytesToString(responseTopicHeader);
try {
pendingRequestCount.getAndIncrement();
AsyncCallbackTemplate.withCallbackAndTimeout(handler.handle(request),
response -> {
pendingRequestCount.decrementAndGet();
response.getHeaders().put(REQUEST_ID_HEADER, uuidToBytes(requestId));
responseTemplate.send(responseTopic, response, null);
},
e -> {
pendingRequestCount.decrementAndGet();
if (e.getCause() != null && e.getCause() instanceof TimeoutException) {
log.warn("[{}] Timeout to process the request: {}", requestId, request, e);
} else {
log.trace("[{}] Failed to process the request: {}", requestId, request, e);
}
},
requestTimeout,
timeoutExecutor,
callbackExecutor);
} catch (Throwable e) {
pendingRequestCount.decrementAndGet();
log.warn("[{}] Failed to process the request: {}", requestId, request, e);
long currentTime = System.currentTimeMillis();
long requestTime = bytesToLong(request.getHeaders().get(REQUEST_TIME));
if (requestTime + requestTimeout >= currentTime) {
byte[] requestIdHeader = request.getHeaders().get(REQUEST_ID_HEADER);
if (requestIdHeader == null) {
log.error("[{}] Missing requestId in header", request);
return;
}
byte[] responseTopicHeader = request.getHeaders().get(RESPONSE_TOPIC_HEADER);
if (responseTopicHeader == null) {
log.error("[{}] Missing response topic in header", request);
return;
}
UUID requestId = bytesToUuid(requestIdHeader);
String responseTopic = bytesToString(responseTopicHeader);
try {
pendingRequestCount.getAndIncrement();
AsyncCallbackTemplate.withCallbackAndTimeout(handler.handle(request),
response -> {
pendingRequestCount.decrementAndGet();
response.getHeaders().put(REQUEST_ID_HEADER, uuidToBytes(requestId));
responseTemplate.send(responseTopic, response, null);
},
e -> {
pendingRequestCount.decrementAndGet();
if (e.getCause() != null && e.getCause() instanceof TimeoutException) {
log.warn("[{}] Timeout to process the request: {}", requestId, request, e);
} else {
log.trace("[{}] Failed to process the request: {}", requestId, request, e);
}
},
requestTimeout,
timeoutExecutor,
callbackExecutor);
} catch (Throwable e) {
pendingRequestCount.decrementAndGet();
log.warn("[{}] Failed to process the request: {}", requestId, request, e);
}
}
});
requestTemplate.commit();

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

@ -1,3 +1,18 @@
/**
* Copyright © 2016-2020 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.common;
import lombok.Data;

50
common/queue/src/main/java/org/thingsboard/server/kafka/AbstractTbKafkaTemplate.java

@ -1,50 +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.kafka;
import lombok.extern.slf4j.Slf4j;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.UUID;
/**
* Created by ashvayka on 25.09.18.
*/
@Slf4j
public abstract class AbstractTbKafkaTemplate {
protected byte[] uuidToBytes(UUID uuid) {
ByteBuffer buf = ByteBuffer.allocate(16);
buf.putLong(uuid.getMostSignificantBits());
buf.putLong(uuid.getLeastSignificantBits());
return buf.array();
}
protected static UUID bytesToUuid(byte[] bytes) {
ByteBuffer bb = ByteBuffer.wrap(bytes);
long firstLong = bb.getLong();
long secondLong = bb.getLong();
return new UUID(firstLong, secondLong);
}
protected byte[] stringToBytes(String string) {
return string.getBytes(StandardCharsets.UTF_8);
}
protected String bytesToString(byte[] data) {
return new String(data, StandardCharsets.UTF_8);
}
}

66
common/queue/src/main/java/org/thingsboard/server/kafka/AsyncCallbackTemplate.java

@ -1,66 +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.kafka;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import java.util.concurrent.Executor;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
/**
* Created by ashvayka on 05.10.18.
*/
public class AsyncCallbackTemplate {
public static <T> void withCallbackAndTimeout(ListenableFuture<T> future,
Consumer<T> onSuccess,
Consumer<Throwable> onFailure,
long timeoutInMs,
ScheduledExecutorService timeoutExecutor,
Executor callbackExecutor) {
future = Futures.withTimeout(future, timeoutInMs, TimeUnit.MILLISECONDS, timeoutExecutor);
withCallback(future, onSuccess, onFailure, callbackExecutor);
}
public static <T> void withCallback(ListenableFuture<T> future, Consumer<T> onSuccess,
Consumer<Throwable> onFailure, Executor executor) {
FutureCallback<T> callback = new FutureCallback<T>() {
@Override
public void onSuccess(T result) {
try {
onSuccess.accept(result);
} catch (Throwable th) {
onFailure(th);
}
}
@Override
public void onFailure(Throwable t) {
onFailure.accept(t);
}
};
if (executor != null) {
Futures.addCallback(future, callback, executor);
} else {
Futures.addCallback(future, callback);
}
}
}

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

@ -1,3 +1,18 @@
/**
* 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.kafka;
import org.apache.kafka.clients.consumer.ConsumerRecord;

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

@ -1,3 +1,18 @@
/**
* 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.kafka;
import lombok.AllArgsConstructor;

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

@ -15,16 +15,17 @@
*/
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 org.apache.kafka.clients.admin.*;
import org.apache.kafka.clients.consumer.ConsumerRecords;
import org.apache.kafka.clients.consumer.KafkaConsumer;
import org.apache.kafka.clients.admin.AdminClient;
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.common.KafkaFuture;
import org.thingsboard.server.TbQueueAdmin;
import java.time.Duration;
import java.util.Collections;
import java.util.Properties;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
@ -40,6 +41,19 @@ public class TBKafkaAdmin implements TbQueueAdmin {
client = AdminClient.create(settings.toProps());
}
@Override
public ListenableFuture<Void> createTopicIfNotExists(String topic) {
KafkaFuture<TopicDescription> topicDescriptionFuture = client.describeTopics(Collections.singleton(topic)).values().get(topic);
ListenableFuture<TopicDescription> topicFuture = JdkFutureAdapters.listenInPoolThread(topicDescriptionFuture);
return Futures.transformAsync(topicFuture, topicDescription -> {
KafkaFuture<Void> resultFuture = createTopic(new NewTopic(topic, 1, (short) 1)).values().get(topic);
return JdkFutureAdapters.listenInPoolThread(resultFuture);
});
}
public void waitForTopic(String topic, long timeout, TimeUnit timeoutUnit) throws InterruptedException, TimeoutException {
synchronized (this) {
long timeoutExpiredMs = System.currentTimeMillis() + timeoutUnit.toMillis(timeout);
@ -54,7 +68,7 @@ public class TBKafkaAdmin implements TbQueueAdmin {
}
}
public CreateTopicsResult createTopic(NewTopic topic){
public CreateTopicsResult createTopic(NewTopic topic) {
return client.createTopics(Collections.singletonList(topic));
}
@ -67,10 +81,4 @@ public class TBKafkaAdmin implements TbQueueAdmin {
return false;
}
}
@Override
public ListenableFuture<Void> createTopicIfNotExists(String topic) {
return null;
}
}

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

@ -31,7 +31,6 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Properties;
import java.util.UUID;
/**
* Created by ashvayka on 24.09.18.
@ -42,15 +41,11 @@ public class TBKafkaConsumerTemplate<T extends TbQueueMsg> implements TbQueueCon
private final KafkaConsumer<String, byte[]> consumer;
private final TbKafkaDecoder<T> decoder;
@Builder.Default
private TbKafkaRequestIdExtractor<T> requestIdExtractor = ((response) -> null);
@Getter
private final String topic;
@Builder
private TBKafkaConsumerTemplate(TbKafkaSettings settings, TbKafkaDecoder<T> decoder,
TbKafkaRequestIdExtractor<T> requestIdExtractor,
String clientId, String groupId, String topic,
boolean autoCommit, int autoCommitIntervalMs,
int maxPollRecords) {
@ -68,7 +63,6 @@ public class TBKafkaConsumerTemplate<T extends TbQueueMsg> implements TbQueueCon
}
this.consumer = new KafkaConsumer<>(props);
this.decoder = decoder;
this.requestIdExtractor = requestIdExtractor;
this.topic = topic;
}
@ -105,22 +99,8 @@ public class TBKafkaConsumerTemplate<T extends TbQueueMsg> implements TbQueueCon
consumer.unsubscribe();
}
// public void subscribe() {
// 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 {
return decoder.decode(new KafkaTbQueueMsg(record));
}
public UUID extractRequestId(T value) {
return requestIdExtractor.extractRequestId(value);
}
}

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

@ -15,9 +15,6 @@
*/
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.Getter;
import lombok.extern.slf4j.Slf4j;
@ -31,7 +28,6 @@ import org.apache.kafka.common.header.internals.RecordHeader;
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;
@ -91,12 +87,12 @@ public class TBKafkaProducerTemplate<T extends TbQueueMsg> implements TbQueuePro
}
@Override
public ListenableFuture<TbQueueMsgMetadata> send(T msg, TbQueueCallback callback) {
return send(defaultTopic, msg, callback);
public void send(T msg, TbQueueCallback callback) {
send(defaultTopic, msg, callback);
}
@Override
public ListenableFuture<TbQueueMsgMetadata> send(String topic, T msg, TbQueueCallback callback) {
public void send(String topic, T msg, TbQueueCallback callback) {
String key = msg.getKey().toString();
byte[] data = msg.getData();
ProducerRecord<String, byte[]> record;
@ -111,42 +107,8 @@ public class TBKafkaProducerTemplate<T extends TbQueueMsg> implements TbQueuePro
callback.onFailure(exception);
}
});
return Futures.transform(JdkFutureAdapters.listenInPoolThread(result), metadata -> new KafkaTbQueueMsgMetadata(metadata));
}
// public Future<RecordMetadata> send(String key, T value, Callback callback) {
// return send(key, value, null, 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) {
// 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, T value) {
if (partitioner == null) {
return null;

213
common/queue/src/main/java/org/thingsboard/server/kafka/TbKafkaRequestTemplate.java

@ -1,213 +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.kafka;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.SettableFuture;
import lombok.Builder;
import lombok.extern.slf4j.Slf4j;
import org.apache.kafka.clients.admin.CreateTopicsResult;
import org.apache.kafka.clients.admin.NewTopic;
import org.apache.kafka.clients.consumer.ConsumerRecords;
import org.apache.kafka.clients.producer.Callback;
import org.apache.kafka.clients.producer.RecordMetadata;
import org.apache.kafka.common.errors.InterruptException;
import org.apache.kafka.common.errors.TopicExistsException;
import org.apache.kafka.common.header.Header;
import org.apache.kafka.common.header.internals.RecordHeader;
import java.io.IOException;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeoutException;
/**
* Created by ashvayka on 25.09.18.
*/
@Slf4j
public class TbKafkaRequestTemplate<Request, Response> extends AbstractTbKafkaTemplate {
private final TBKafkaProducerTemplate<Request> requestTemplate;
private final TBKafkaConsumerTemplate<Response> responseTemplate;
private final ConcurrentMap<UUID, ResponseMetaData<Response>> pendingRequests;
private final boolean internalExecutor;
private final ExecutorService executor;
private final long maxRequestTimeout;
private final long maxPendingRequests;
private final long pollInterval;
private volatile long tickTs = 0L;
private volatile long tickSize = 0L;
private volatile boolean stopped = false;
@Builder
public TbKafkaRequestTemplate(TBKafkaProducerTemplate<Request> requestTemplate,
TBKafkaConsumerTemplate<Response> responseTemplate,
long maxRequestTimeout,
long maxPendingRequests,
long pollInterval,
ExecutorService executor) {
this.requestTemplate = requestTemplate;
this.responseTemplate = responseTemplate;
this.pendingRequests = new ConcurrentHashMap<>();
this.maxRequestTimeout = maxRequestTimeout;
this.maxPendingRequests = maxPendingRequests;
this.pollInterval = pollInterval;
if (executor != null) {
internalExecutor = false;
this.executor = executor;
} else {
internalExecutor = true;
this.executor = Executors.newSingleThreadExecutor();
}
}
public void init() {
try {
TBKafkaAdmin admin = new TBKafkaAdmin(this.requestTemplate.getSettings());
CreateTopicsResult result = admin.createTopic(new NewTopic(responseTemplate.getTopic(), 1, (short) 1));
result.all().get();
} catch (Exception e) {
if ((e instanceof TopicExistsException) || (e.getCause() != null && e.getCause() instanceof TopicExistsException)) {
log.trace("[{}] Topic already exists. ", responseTemplate.getTopic());
} else {
log.info("[{}] Failed to create topic: {}", responseTemplate.getTopic(), e.getMessage(), e);
throw new RuntimeException(e);
}
}
this.requestTemplate.init();
tickTs = System.currentTimeMillis();
responseTemplate.subscribe();
executor.submit(() -> {
long nextCleanupMs = 0L;
while (!stopped) {
try {
ConsumerRecords<String, byte[]> responses = responseTemplate.poll(Duration.ofMillis(pollInterval));
if (responses.count() > 0) {
log.trace("Polling responses completed, consumer records count [{}]", responses.count());
}
responses.forEach(response -> {
log.trace("Received response to Kafka Template request: {}", response);
Header requestIdHeader = response.headers().lastHeader(TbKafkaSettings.REQUEST_ID_HEADER);
Response decodedResponse = null;
UUID requestId = null;
if (requestIdHeader == null) {
try {
decodedResponse = responseTemplate.decode(response);
requestId = responseTemplate.extractRequestId(decodedResponse);
} catch (IOException e) {
log.error("Failed to decode response", e);
}
} else {
requestId = bytesToUuid(requestIdHeader.value());
}
if (requestId == null) {
log.error("[{}] Missing requestId in header and body", response);
} else {
log.trace("[{}] Response received", requestId);
ResponseMetaData<Response> expectedResponse = pendingRequests.remove(requestId);
if (expectedResponse == null) {
log.trace("[{}] Invalid or stale request", requestId);
} else {
try {
if (decodedResponse == null) {
decodedResponse = responseTemplate.decode(response);
}
expectedResponse.future.set(decodedResponse);
} catch (IOException e) {
expectedResponse.future.setException(e);
}
}
}
});
tickTs = System.currentTimeMillis();
tickSize = pendingRequests.size();
if (nextCleanupMs < tickTs) {
//cleanup;
pendingRequests.forEach((key, value) -> {
if (value.expTime < tickTs) {
ResponseMetaData<Response> staleRequest = pendingRequests.remove(key);
if (staleRequest != null) {
log.trace("[{}] Request timeout detected, expTime [{}], tickTs [{}]", key, staleRequest.expTime, tickTs);
staleRequest.future.setException(new TimeoutException());
}
}
});
nextCleanupMs = tickTs + maxRequestTimeout;
}
} catch (InterruptException ie) {
if (!stopped) {
log.warn("Fetching data from kafka was interrupted.", ie);
}
} catch (Throwable e) {
log.warn("Failed to obtain responses from queue.", e);
try {
Thread.sleep(pollInterval);
} catch (InterruptedException e2) {
log.trace("Failed to wait until the server has capacity to handle new responses", e2);
}
}
}
});
}
public void stop() {
stopped = true;
if (internalExecutor) {
executor.shutdownNow();
}
}
public ListenableFuture<Response> post(String key, Request request) {
if (tickSize > maxPendingRequests) {
return Futures.immediateFailedFuture(new RuntimeException("Pending request map is full!"));
}
UUID requestId = UUID.randomUUID();
List<Header> headers = new ArrayList<>(2);
headers.add(new RecordHeader(TbKafkaSettings.REQUEST_ID_HEADER, uuidToBytes(requestId)));
headers.add(new RecordHeader(TbKafkaSettings.RESPONSE_TOPIC_HEADER, stringToBytes(responseTemplate.getTopic())));
SettableFuture<Response> future = SettableFuture.create();
ResponseMetaData<Response> responseMetaData = new ResponseMetaData<>(tickTs + maxRequestTimeout, future);
pendingRequests.putIfAbsent(requestId, responseMetaData);
log.trace("[{}] Sending request, key [{}], expTime [{}]", requestId, key, responseMetaData.expTime);
requestTemplate.send(key, request, headers, (metadata, exception) -> {
if (exception != null) {
log.trace("[{}] Failed to post the request", requestId, exception);
} else {
log.trace("[{}] Posted the request: {}", requestId, metadata);
}
});
return future;
}
private static class ResponseMetaData<T> {
private final long expTime;
private final SettableFuture<T> future;
ResponseMetaData(long ts, SettableFuture<T> future) {
this.expTime = ts;
this.future = future;
}
}
}

161
common/queue/src/main/java/org/thingsboard/server/kafka/TbKafkaResponseTemplate.java

@ -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.kafka;
import lombok.Builder;
import lombok.extern.slf4j.Slf4j;
import org.apache.kafka.clients.consumer.ConsumerRecords;
import org.apache.kafka.common.errors.InterruptException;
import org.apache.kafka.common.header.Header;
import org.apache.kafka.common.header.internals.RecordHeader;
import java.time.Duration;
import java.util.Collections;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicInteger;
/**
* Created by ashvayka on 25.09.18.
*/
@Slf4j
public class TbKafkaResponseTemplate<Request, Response> extends AbstractTbKafkaTemplate {
private final TBKafkaConsumerTemplate<Request> requestTemplate;
private final TBKafkaProducerTemplate<Response> responseTemplate;
private final TbKafkaHandler<Request, Response> handler;
private final ConcurrentMap<UUID, String> pendingRequests;
private final ExecutorService loopExecutor;
private final ScheduledExecutorService timeoutExecutor;
private final ExecutorService callbackExecutor;
private final int maxPendingRequests;
private final long requestTimeout;
private final long pollInterval;
private volatile boolean stopped = false;
private final AtomicInteger pendingRequestCount = new AtomicInteger();
@Builder
public TbKafkaResponseTemplate(TBKafkaConsumerTemplate<Request> requestTemplate,
TBKafkaProducerTemplate<Response> responseTemplate,
TbKafkaHandler<Request, Response> handler,
long pollInterval,
long requestTimeout,
int maxPendingRequests,
ExecutorService executor) {
this.requestTemplate = requestTemplate;
this.responseTemplate = responseTemplate;
this.handler = handler;
this.pendingRequests = new ConcurrentHashMap<>();
this.maxPendingRequests = maxPendingRequests;
this.pollInterval = pollInterval;
this.requestTimeout = requestTimeout;
this.callbackExecutor = executor;
this.timeoutExecutor = Executors.newSingleThreadScheduledExecutor();
this.loopExecutor = Executors.newSingleThreadExecutor();
}
public void init() {
this.responseTemplate.init();
requestTemplate.subscribe();
loopExecutor.submit(() -> {
while (!stopped) {
try {
while (pendingRequestCount.get() >= maxPendingRequests) {
try {
Thread.sleep(pollInterval);
} catch (InterruptedException e) {
log.trace("Failed to wait until the server has capacity to handle new requests", e);
}
}
ConsumerRecords<String, byte[]> requests = requestTemplate.poll(Duration.ofMillis(pollInterval));
requests.forEach(request -> {
Header requestIdHeader = request.headers().lastHeader(TbKafkaSettings.REQUEST_ID_HEADER);
if (requestIdHeader == null) {
log.error("[{}] Missing requestId in header", request);
return;
}
UUID requestId = bytesToUuid(requestIdHeader.value());
if (requestId == null) {
log.error("[{}] Missing requestId in header and body", request);
return;
}
Header responseTopicHeader = request.headers().lastHeader(TbKafkaSettings.RESPONSE_TOPIC_HEADER);
if (responseTopicHeader == null) {
log.error("[{}] Missing response topic in header", request);
return;
}
String responseTopic = bytesToString(responseTopicHeader.value());
try {
pendingRequestCount.getAndIncrement();
Request decodedRequest = requestTemplate.decode(request);
AsyncCallbackTemplate.withCallbackAndTimeout(handler.handle(decodedRequest),
response -> {
pendingRequestCount.decrementAndGet();
reply(requestId, responseTopic, response);
},
e -> {
pendingRequestCount.decrementAndGet();
if (e.getCause() != null && e.getCause() instanceof TimeoutException) {
log.warn("[{}] Timedout to process the request: {}", requestId, request, e);
} else {
log.trace("[{}] Failed to process the request: {}", requestId, request, e);
}
},
requestTimeout,
timeoutExecutor,
callbackExecutor);
} catch (Throwable e) {
pendingRequestCount.decrementAndGet();
log.warn("[{}] Failed to process the request: {}", requestId, request, e);
}
});
} catch (InterruptException ie) {
if (!stopped) {
log.warn("Fetching data from kafka was interrupted.", ie);
}
} catch (Throwable e) {
log.warn("Failed to obtain messages from queue.", e);
try {
Thread.sleep(pollInterval);
} catch (InterruptedException e2) {
log.trace("Failed to wait until the server has capacity to handle new requests", e2);
}
}
}
});
}
public void stop() {
stopped = true;
if (timeoutExecutor != null) {
timeoutExecutor.shutdownNow();
}
if (loopExecutor != null) {
loopExecutor.shutdownNow();
}
}
private void reply(UUID requestId, String topic, Response response) {
responseTemplate.send(topic, requestId.toString(), response, Collections.singletonList(new RecordHeader(TbKafkaSettings.REQUEST_ID_HEADER, uuidToBytes(requestId))), null);
}
}

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

@ -35,22 +35,22 @@ public class TbKafkaSettings {
static final String REQUEST_ID_HEADER = "requestId";
static final String RESPONSE_TOPIC_HEADER = "responseTopic";
@Value("${kafka.bootstrap.servers}")
@Value("${queue.kafka.bootstrap.servers}")
private String servers;
@Value("${kafka.acks}")
@Value("${queue.kafka.acks}")
private String acks;
@Value("${kafka.retries}")
@Value("${queue.queue.kafka.retries}")
private int retries;
@Value("${kafka.batch.size}")
@Value("${queue.kafka.batch.size}")
private int batchSize;
@Value("${kafka.linger.ms}")
@Value("${queue.kafka.linger.ms}")
private long lingerMs;
@Value("${kafka.buffer.memory}")
@Value("${queue.kafka.buffer.memory}")
private long bufferMemory;
@Value("${kafka.other:#{null}}")

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

@ -1,3 +1,18 @@
/**
* 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.memory;
import org.thingsboard.server.TbQueueMsg;

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

@ -1,3 +1,18 @@
/**
* 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.memory;
import org.thingsboard.server.TbQueueConsumer;

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

@ -1,11 +1,23 @@
/**
* 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.memory;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import lombok.Data;
import org.thingsboard.server.TbQueueCallback;
import org.thingsboard.server.TbQueueMsg;
import org.thingsboard.server.TbQueueMsgMetadata;
import org.thingsboard.server.TbQueueProducer;
@Data
@ -15,6 +27,10 @@ public class InMemoryTbQueueProducer<T extends TbQueueMsg> implements TbQueuePro
private final String defaultTopic;
public InMemoryTbQueueProducer(String defaultTopic) {
this.defaultTopic = defaultTopic;
}
@Override
public void init() {
@ -26,20 +42,18 @@ public class InMemoryTbQueueProducer<T extends TbQueueMsg> implements TbQueuePro
}
@Override
public ListenableFuture<TbQueueMsgMetadata> send(T msg, TbQueueCallback callback) {
return send(defaultTopic, msg, callback);
public void send(T msg, TbQueueCallback callback) {
send(defaultTopic, msg, callback);
}
@Override
public ListenableFuture<TbQueueMsgMetadata> send(String topic, T msg, TbQueueCallback callback) {
public void 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);
}
}
}

79
common/queue/src/main/java/org/thingsboard/server/provider/InMemoryTbCoreQueueProvider.java

@ -0,0 +1,79 @@
/**
* 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.provider;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.stereotype.Component;
import org.thingsboard.server.TbQueueConsumer;
import org.thingsboard.server.TbQueueCoreSettings;
import org.thingsboard.server.TbQueueProducer;
import org.thingsboard.server.common.TbProtoQueueMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg;
import org.thingsboard.server.gen.transport.TransportProtos.TransportApiRequestMsg;
import org.thingsboard.server.gen.transport.TransportProtos.TransportApiResponseMsg;
import org.thingsboard.server.memory.InMemoryTbQueueConsumer;
import org.thingsboard.server.memory.InMemoryTbQueueProducer;
@Slf4j
@Component
@ConditionalOnExpression("('${service.type:null}'=='monolith' || '${service.type:null}'=='tb-core') && '${queue.type:null}'=='in-memory'")
public class InMemoryTbCoreQueueProvider implements TbCoreQueueProvider {
private final TbQueueCoreSettings coreSettings;
public InMemoryTbCoreQueueProvider(TbQueueCoreSettings coreSettings) {
this.coreSettings = coreSettings;
}
@Override
public TbQueueProducer<TbProtoQueueMsg<ToTransportMsg>> getTransportMsgProducer() {
InMemoryTbQueueProducer<TbProtoQueueMsg<ToTransportMsg>> producer = new InMemoryTbQueueProducer<>(coreSettings.getTopic());
return producer;
}
@Override
public TbQueueProducer<TbProtoQueueMsg<ToRuleEngineMsg>> getRuleEngineMsgProducer() {
InMemoryTbQueueProducer<TbProtoQueueMsg<ToRuleEngineMsg>> producer = new InMemoryTbQueueProducer<>(coreSettings.getTopic());
return producer;
}
@Override
public TbQueueProducer<TbProtoQueueMsg<ToCoreMsg>> getTbCoreMsgProducer() {
InMemoryTbQueueProducer<TbProtoQueueMsg<ToCoreMsg>> producer = new InMemoryTbQueueProducer<>(coreSettings.getTopic());
return producer;
}
@Override
public TbQueueConsumer<TbProtoQueueMsg<ToCoreMsg>> getToCoreMsgConsumer() {
InMemoryTbQueueConsumer<TbProtoQueueMsg<ToCoreMsg>> consumer = new InMemoryTbQueueConsumer<>(coreSettings.getTopic());
return consumer;
}
@Override
public TbQueueConsumer<TbProtoQueueMsg<TransportApiRequestMsg>> getTransportApiRequestConsumer() {
InMemoryTbQueueConsumer<TbProtoQueueMsg<TransportApiRequestMsg>> consumer = new InMemoryTbQueueConsumer<>(coreSettings.getTopic());
return consumer;
}
@Override
public TbQueueProducer<TbProtoQueueMsg<TransportApiResponseMsg>> getTransportApiResponseProducer() {
InMemoryTbQueueProducer<TbProtoQueueMsg<TransportApiResponseMsg>> producer = new InMemoryTbQueueProducer<>(coreSettings.getTopic());
return producer;
}
}

79
common/queue/src/main/java/org/thingsboard/server/provider/InMemoryTransportQueueProvider.java

@ -0,0 +1,79 @@
/**
* 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.provider;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.stereotype.Component;
import org.thingsboard.server.TbQueueConsumer;
import org.thingsboard.server.TbQueueProducer;
import org.thingsboard.server.TbQueueRequestTemplate;
import org.thingsboard.server.TbQueueTransportApiSettings;
import org.thingsboard.server.common.DefaultTbQueueRequestTemplate;
import org.thingsboard.server.common.TbProtoQueueMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg;
import org.thingsboard.server.gen.transport.TransportProtos.TransportApiRequestMsg;
import org.thingsboard.server.gen.transport.TransportProtos.TransportApiResponseMsg;
import org.thingsboard.server.memory.InMemoryTbQueueConsumer;
import org.thingsboard.server.memory.InMemoryTbQueueProducer;
@Component
@ConditionalOnExpression("('${service.type:null}'=='monolith' || '${service.type:null}'=='tb-transport') && '${queue.type:null}'=='in-memory'")
@Slf4j
public class InMemoryTransportQueueProvider implements TransportQueueProvider {
private final TbQueueTransportApiSettings transportApiSettings;
public InMemoryTransportQueueProvider(TbQueueTransportApiSettings transportApiSettings) {
this.transportApiSettings = transportApiSettings;
}
@Override
public TbQueueRequestTemplate<TbProtoQueueMsg<TransportApiRequestMsg>, TbProtoQueueMsg<TransportApiResponseMsg>> getTransportApiRequestTemplate() {
InMemoryTbQueueProducer<TbProtoQueueMsg<TransportApiRequestMsg>> producer = new InMemoryTbQueueProducer<>(transportApiSettings.getRequestsTopic());
InMemoryTbQueueConsumer<TbProtoQueueMsg<TransportApiResponseMsg>> consumer = new InMemoryTbQueueConsumer<>(transportApiSettings.getResponsesTopic());
DefaultTbQueueRequestTemplate.DefaultTbQueueRequestTemplateBuilder
<TbProtoQueueMsg<TransportApiRequestMsg>, TbProtoQueueMsg<TransportApiResponseMsg>> templateBuilder = DefaultTbQueueRequestTemplate.builder();
templateBuilder.requestTemplate(producer);
templateBuilder.responseTemplate(consumer);
templateBuilder.maxPendingRequests(transportApiSettings.getMaxPendingRequests());
templateBuilder.maxRequestTimeout(transportApiSettings.getMaxRequestsTimeout());
templateBuilder.pollInterval(transportApiSettings.getResponsePollInterval());
return templateBuilder.build();
}
@Override
public TbQueueProducer<TbProtoQueueMsg<ToRuleEngineMsg>> getRuleEngineMsgProducer() {
InMemoryTbQueueProducer<TbProtoQueueMsg<ToRuleEngineMsg>> producer = new InMemoryTbQueueProducer<>(transportApiSettings.getRequestsTopic());
return producer;
}
@Override
public TbQueueProducer<TbProtoQueueMsg<ToCoreMsg>> getTbCoreMsgProducer() {
InMemoryTbQueueProducer<TbProtoQueueMsg<ToCoreMsg>> producer = new InMemoryTbQueueProducer<>(transportApiSettings.getRequestsTopic());
return producer;
}
@Override
public TbQueueConsumer<TbProtoQueueMsg<ToTransportMsg>> getTransportNotificationsConsumer() {
InMemoryTbQueueConsumer<TbProtoQueueMsg<ToTransportMsg>> consumer = new InMemoryTbQueueConsumer<>(transportApiSettings.getResponsesTopic());
return consumer;
}
}

88
common/queue/src/main/java/org/thingsboard/server/provider/KafkaTbCoreQueueProvider.java

@ -1,42 +1,102 @@
/**
* 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.provider;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.stereotype.Component;
import org.thingsboard.server.TbQueueConsumer;
import org.thingsboard.server.TbQueueCoreSettings;
import org.thingsboard.server.TbQueueProducer;
import org.thingsboard.server.common.TbProtoQueueMsg;
import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg;
import org.thingsboard.server.gen.transport.TransportProtos.TransportApiRequestMsg;
import org.thingsboard.server.gen.transport.TransportProtos.TransportApiResponseMsg;
import org.thingsboard.server.kafka.TBKafkaConsumerTemplate;
import org.thingsboard.server.kafka.TBKafkaProducerTemplate;
import org.thingsboard.server.kafka.TbKafkaSettings;
import org.thingsboard.server.kafka.TbNodeIdProvider;
@Component
@ConditionalOnExpression("'${service.type:null}'=='monolith' || '${service.type:null}'=='tb-core') && ${queue.type:null}'=='kafka'")
public class KafkaTbCoreQueueProvider implements TbCoreQueueProvider{
@ConditionalOnExpression("('${service.type:null}'=='monolith' || '${service.type:null}'=='tb-core') && '${queue.type:null}'=='kafka'")
public class KafkaTbCoreQueueProvider implements TbCoreQueueProvider {
private final TbKafkaSettings kafkaSettings;
private final TbNodeIdProvider nodeIdProvider;
private final TbQueueCoreSettings coreSettings;
public KafkaTbCoreQueueProvider(TbKafkaSettings kafkaSettings, TbNodeIdProvider nodeIdProvider, TbQueueCoreSettings coreSettings) {
this.kafkaSettings = kafkaSettings;
this.nodeIdProvider = nodeIdProvider;
this.coreSettings = coreSettings;
}
@Override
public TbQueueProducer<TbProtoQueueMsg<TransportProtos.ToTransportMsg>> getTransportMsgProducer() {
return null;
public TbQueueProducer<TbProtoQueueMsg<ToTransportMsg>> getTransportMsgProducer() {
TBKafkaProducerTemplate.TBKafkaProducerTemplateBuilder<TbProtoQueueMsg<ToTransportMsg>> requestBuilder = TBKafkaProducerTemplate.builder();
requestBuilder.settings(kafkaSettings);
requestBuilder.clientId("producer-core-" + nodeIdProvider.getNodeId());
requestBuilder.defaultTopic(coreSettings.getTopic());
return requestBuilder.build();
}
@Override
public TbQueueProducer<TbProtoQueueMsg<TransportProtos.ToRuleEngineMsg>> getRuleEngineMsgProducer() {
return null;
public TbQueueProducer<TbProtoQueueMsg<ToRuleEngineMsg>> getRuleEngineMsgProducer() {
TBKafkaProducerTemplate.TBKafkaProducerTemplateBuilder<TbProtoQueueMsg<ToRuleEngineMsg>> requestBuilder = TBKafkaProducerTemplate.builder();
requestBuilder.settings(kafkaSettings);
requestBuilder.clientId("producer-core-" + nodeIdProvider.getNodeId());
requestBuilder.defaultTopic(coreSettings.getTopic());
return requestBuilder.build();
}
@Override
public TbQueueProducer<TbProtoQueueMsg<TransportProtos.ToCoreMsg>> getTbCoreMsgProducer() {
return null;
public TbQueueProducer<TbProtoQueueMsg<ToCoreMsg>> getTbCoreMsgProducer() {
TBKafkaProducerTemplate.TBKafkaProducerTemplateBuilder<TbProtoQueueMsg<ToCoreMsg>> requestBuilder = TBKafkaProducerTemplate.builder();
requestBuilder.settings(kafkaSettings);
requestBuilder.clientId("producer-core-" + nodeIdProvider.getNodeId());
requestBuilder.defaultTopic(coreSettings.getTopic());
return requestBuilder.build();
}
@Override
public TbQueueConsumer<TbProtoQueueMsg<TransportProtos.ToCoreMsg>> getToCoreMsgConsumer() {
return null;
public TbQueueConsumer<TbProtoQueueMsg<ToCoreMsg>> getToCoreMsgConsumer() {
TBKafkaConsumerTemplate.TBKafkaConsumerTemplateBuilder<TbProtoQueueMsg<ToCoreMsg>> responseBuilder = TBKafkaConsumerTemplate.builder();
responseBuilder.settings(kafkaSettings);
responseBuilder.topic(coreSettings.getTopic());
responseBuilder.clientId("consumer-transport-" + nodeIdProvider.getNodeId());
responseBuilder.groupId("rule-engine-node-" + nodeIdProvider.getNodeId());
responseBuilder.autoCommit(true);
//TODO: 2.5
// responseBuilder.autoCommitIntervalMs(autoCommitInterval);
// responseBuilder.decoder(new TransportApiResponseDecoder());
return responseBuilder.build();
}
@Override
public TbQueueConsumer<TbProtoQueueMsg<TransportProtos.TransportApiRequestMsg>> getTransportApiRequestConsumer() {
public TbQueueConsumer<TbProtoQueueMsg<TransportApiRequestMsg>> getTransportApiRequestConsumer() {
return null;
}
@Override
public TbQueueProducer<TbProtoQueueMsg<TransportProtos.TransportApiResponseMsg>> getTransportApiResponseProducer() {
return null;
public TbQueueProducer<TbProtoQueueMsg<TransportApiResponseMsg>> getTransportApiResponseProducer() {
TBKafkaProducerTemplate.TBKafkaProducerTemplateBuilder<TbProtoQueueMsg<TransportApiResponseMsg>> requestBuilder = TBKafkaProducerTemplate.builder();
requestBuilder.settings(kafkaSettings);
requestBuilder.clientId("producer-core-" + nodeIdProvider.getNodeId());
requestBuilder.defaultTopic(coreSettings.getTopic());
return requestBuilder.build();
}
}

70
common/queue/src/main/java/org/thingsboard/server/provider/KafkaTransportQueueProvider.java

@ -1,3 +1,18 @@
/**
* 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.provider;
import lombok.extern.slf4j.Slf4j;
@ -6,30 +21,77 @@ import org.springframework.stereotype.Component;
import org.thingsboard.server.TbQueueConsumer;
import org.thingsboard.server.TbQueueProducer;
import org.thingsboard.server.TbQueueRequestTemplate;
import org.thingsboard.server.TbQueueTransportApiSettings;
import org.thingsboard.server.common.DefaultTbQueueRequestTemplate;
import org.thingsboard.server.common.TbProtoQueueMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg;
import org.thingsboard.server.gen.transport.TransportProtos.TransportApiRequestMsg;
import org.thingsboard.server.gen.transport.TransportProtos.TransportApiResponseMsg;
import org.thingsboard.server.kafka.TBKafkaConsumerTemplate;
import org.thingsboard.server.kafka.TBKafkaProducerTemplate;
import org.thingsboard.server.kafka.TbKafkaSettings;
import org.thingsboard.server.kafka.TbNodeIdProvider;
@Component
@ConditionalOnExpression("'${service.type:null}'=='monolith' || '${service.type:null}'=='tb-transport') && ${queue.type:null}'=='kafka'")
@ConditionalOnExpression("('${service.type:null}'=='monolith' || '${service.type:null}'=='tb-transport') && '${queue.type:null}'=='kafka'")
@Slf4j
public class KafkaTransportQueueProvider implements TransportQueueProvider {
private final TbKafkaSettings kafkaSettings;
private final TbNodeIdProvider nodeIdProvider;
private final TbQueueTransportApiSettings transportApiSettings;
public KafkaTransportQueueProvider(TbKafkaSettings kafkaSettings, TbNodeIdProvider nodeIdProvider, TbQueueTransportApiSettings transportApiSettings) {
this.kafkaSettings = kafkaSettings;
this.nodeIdProvider = nodeIdProvider;
this.transportApiSettings = transportApiSettings;
}
@Override
public TbQueueRequestTemplate<TbProtoQueueMsg<TransportApiRequestMsg>, TbProtoQueueMsg<TransportApiResponseMsg>> getTransportApiRequestTemplate() {
return null;
TBKafkaProducerTemplate.TBKafkaProducerTemplateBuilder<TbProtoQueueMsg<TransportApiRequestMsg>> requestBuilder = TBKafkaProducerTemplate.builder();
requestBuilder.settings(kafkaSettings);
requestBuilder.clientId("producer-transport-" + nodeIdProvider.getNodeId());
requestBuilder.defaultTopic(transportApiSettings.getRequestsTopic());
TBKafkaConsumerTemplate.TBKafkaConsumerTemplateBuilder<TbProtoQueueMsg<TransportApiResponseMsg>> responseBuilder = TBKafkaConsumerTemplate.builder();
responseBuilder.settings(kafkaSettings);
responseBuilder.topic(transportApiSettings.getResponsesTopic());
responseBuilder.clientId("consumer-transport-" + nodeIdProvider.getNodeId());
responseBuilder.groupId("rule-engine-node-" + nodeIdProvider.getNodeId());
responseBuilder.autoCommit(true);
//TODO: 2.5
// responseBuilder.autoCommitIntervalMs(autoCommitInterval);
// responseBuilder.decoder(new TransportApiResponseDecoder());
DefaultTbQueueRequestTemplate.DefaultTbQueueRequestTemplateBuilder
<TbProtoQueueMsg<TransportApiRequestMsg>, TbProtoQueueMsg<TransportApiResponseMsg>> templateBuilder = DefaultTbQueueRequestTemplate.builder();
templateBuilder.requestTemplate(requestBuilder.build());
templateBuilder.responseTemplate(responseBuilder.build());
templateBuilder.maxPendingRequests(transportApiSettings.getMaxPendingRequests());
templateBuilder.maxRequestTimeout(transportApiSettings.getMaxRequestsTimeout());
templateBuilder.pollInterval(transportApiSettings.getResponsePollInterval());
return templateBuilder.build();
}
@Override
public TbQueueProducer<TbProtoQueueMsg<ToRuleEngineMsg>> getRuleEngineMsgProducer() {
return null;
TBKafkaProducerTemplate.TBKafkaProducerTemplateBuilder<TbProtoQueueMsg<ToRuleEngineMsg>> requestBuilder = TBKafkaProducerTemplate.builder();
requestBuilder.settings(kafkaSettings);
requestBuilder.clientId("producer-transport-" + nodeIdProvider.getNodeId());
requestBuilder.defaultTopic(transportApiSettings.getRequestsTopic());
return requestBuilder.build();
}
@Override
public TbQueueProducer<TbProtoQueueMsg<ToCoreMsg>> getTbCoreMsgProducer() {
return null;
TBKafkaProducerTemplate.TBKafkaProducerTemplateBuilder<TbProtoQueueMsg<ToCoreMsg>> requestBuilder = TBKafkaProducerTemplate.builder();
requestBuilder.settings(kafkaSettings);
requestBuilder.clientId("producer-transport-" + nodeIdProvider.getNodeId());
requestBuilder.defaultTopic(transportApiSettings.getRequestsTopic());
return requestBuilder.build();
}
@Override

17
common/queue/src/main/java/org/thingsboard/server/provider/TbCoreQueueProvider.java

@ -1,9 +1,22 @@
/**
* 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.provider;
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.TbProtoQueueMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg;

15
common/queue/src/main/java/org/thingsboard/server/provider/TransportQueueProvider.java

@ -1,3 +1,18 @@
/**
* 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.provider;
import org.thingsboard.server.TbQueueConsumer;

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

@ -5,7 +5,7 @@
* 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
* 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,

Loading…
Cancel
Save