created Aws Sqs Queue (#2534)
* created Aws Sqs Queue * improvement AwsSqs providers * revert package-lock.json * Aws sqs improvements * Aws sqs improvements * Aws sqs improvements * Aws sqs improvements * aws improvements * aws improvements * aws improvements * added visibility timeout to aws queue
This commit is contained in:
parent
c4269023dd
commit
2553cf6b6f
@ -88,7 +88,6 @@ public class RpcController extends BaseController {
|
|||||||
return handleDeviceRPCRequest(false, new DeviceId(UUID.fromString(deviceIdStr)), requestBody);
|
return handleDeviceRPCRequest(false, new DeviceId(UUID.fromString(deviceIdStr)), requestBody);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private DeferredResult<ResponseEntity> handleDeviceRPCRequest(boolean oneWay, DeviceId deviceId, String requestBody) throws ThingsboardException {
|
private DeferredResult<ResponseEntity> handleDeviceRPCRequest(boolean oneWay, DeviceId deviceId, String requestBody) throws ThingsboardException {
|
||||||
try {
|
try {
|
||||||
JsonNode rpcRequestBody = jsonMapper.readTree(requestBody);
|
JsonNode rpcRequestBody = jsonMapper.readTree(requestBody);
|
||||||
|
|||||||
@ -136,6 +136,15 @@ public abstract class AbstractConsumerService<T extends com.google.protobuf.Gene
|
|||||||
@PreDestroy
|
@PreDestroy
|
||||||
public void destroy() {
|
public void destroy() {
|
||||||
stopped = true;
|
stopped = true;
|
||||||
|
|
||||||
|
if (mainConsumer != null) {
|
||||||
|
mainConsumer.unsubscribe();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nfConsumer != null) {
|
||||||
|
nfConsumer.unsubscribe();
|
||||||
|
}
|
||||||
|
|
||||||
if (mainConsumerExecutor != null) {
|
if (mainConsumerExecutor != null) {
|
||||||
mainConsumerExecutor.shutdownNow();
|
mainConsumerExecutor.shutdownNow();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -517,7 +517,7 @@ swagger:
|
|||||||
version: "${SWAGGER_VERSION:2.0}"
|
version: "${SWAGGER_VERSION:2.0}"
|
||||||
|
|
||||||
queue:
|
queue:
|
||||||
type: "${TB_QUEUE_TYPE:in-memory}" # kafka or in-memory
|
type: "${TB_QUEUE_TYPE:in-memory}" # kafka or in-memory or aws-sqs
|
||||||
kafka:
|
kafka:
|
||||||
bootstrap.servers: "${TB_KAFKA_SERVERS:localhost:9092}"
|
bootstrap.servers: "${TB_KAFKA_SERVERS:localhost:9092}"
|
||||||
acks: "${TB_KAFKA_ACKS:all}"
|
acks: "${TB_KAFKA_ACKS:all}"
|
||||||
@ -525,6 +525,12 @@ queue:
|
|||||||
batch.size: "${TB_KAFKA_BATCH_SIZE:16384}"
|
batch.size: "${TB_KAFKA_BATCH_SIZE:16384}"
|
||||||
linger.ms: "${TB_KAFKA_LINGER_MS:1}"
|
linger.ms: "${TB_KAFKA_LINGER_MS:1}"
|
||||||
buffer.memory: "${TB_BUFFER_MEMORY:33554432}"
|
buffer.memory: "${TB_BUFFER_MEMORY:33554432}"
|
||||||
|
aws_sqs:
|
||||||
|
access_key_id: "${TB_QUEUE_AWS_SQS_ACCESS_KEY_ID:YOUR_KEY}"
|
||||||
|
secret_access_key: "${TB_QUEUE_AWS_SQS_SECRET_ACCESS_KEY:YOUR_SECRET}"
|
||||||
|
region: "${TB_QUEUE_AWS_SQS_REGION:YOUR_REGION}"
|
||||||
|
threads_per_topic: "${TB_QUEUE_AWS_SQS_THREADS_PER_TOPIC:1}"
|
||||||
|
visibility_timeout: "${TB_QUEUE_AWS_SQS_VISIBILITY_TIMEOUT:30}" #in seconds
|
||||||
partitions:
|
partitions:
|
||||||
hash_function_name: "${TB_QUEUE_PARTITIONS_HASH_FUNCTION_NAME:murmur3_128}"
|
hash_function_name: "${TB_QUEUE_PARTITIONS_HASH_FUNCTION_NAME:murmur3_128}"
|
||||||
virtual_nodes_size: "${TB_QUEUE_PARTITIONS_VIRTUAL_NODES_SIZE:16}"
|
virtual_nodes_size: "${TB_QUEUE_PARTITIONS_VIRTUAL_NODES_SIZE:16}"
|
||||||
|
|||||||
@ -52,6 +52,11 @@
|
|||||||
<groupId>org.apache.kafka</groupId>
|
<groupId>org.apache.kafka</groupId>
|
||||||
<artifactId>kafka-clients</artifactId>
|
<artifactId>kafka-clients</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.amazonaws</groupId>
|
||||||
|
<artifactId>aws-java-sdk-sqs</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework</groupId>
|
<groupId>org.springframework</groupId>
|
||||||
<artifactId>spring-context-support</artifactId>
|
<artifactId>spring-context-support</artifactId>
|
||||||
|
|||||||
@ -0,0 +1,24 @@
|
|||||||
|
/**
|
||||||
|
* 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.queue;
|
||||||
|
|
||||||
|
import com.google.protobuf.InvalidProtocolBufferException;
|
||||||
|
import org.thingsboard.server.queue.TbQueueMsg;
|
||||||
|
|
||||||
|
public interface TbQueueMsgDecoder<T extends TbQueueMsg> {
|
||||||
|
|
||||||
|
T decode(TbQueueMsg msg) throws InvalidProtocolBufferException;
|
||||||
|
}
|
||||||
@ -25,4 +25,5 @@ public interface TbQueueProducer<T extends TbQueueMsg> {
|
|||||||
|
|
||||||
void send(TopicPartitionInfo tpi, T msg, TbQueueCallback callback);
|
void send(TopicPartitionInfo tpi, T msg, TbQueueCallback callback);
|
||||||
|
|
||||||
|
void stop();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -92,6 +92,8 @@ public class DefaultTbQueueRequestTemplate<Request extends TbQueueMsg, Response
|
|||||||
List<Response> responses = responseTemplate.poll(pollInterval);
|
List<Response> responses = responseTemplate.poll(pollInterval);
|
||||||
if (responses.size() > 0) {
|
if (responses.size() > 0) {
|
||||||
log.trace("Polling responses completed, consumer records count [{}]", responses.size());
|
log.trace("Polling responses completed, consumer records count [{}]", responses.size());
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
responses.forEach(response -> {
|
responses.forEach(response -> {
|
||||||
log.trace("Received response to Kafka Template request: {}", response);
|
log.trace("Received response to Kafka Template request: {}", response);
|
||||||
@ -145,6 +147,15 @@ public class DefaultTbQueueRequestTemplate<Request extends TbQueueMsg, Response
|
|||||||
@Override
|
@Override
|
||||||
public void stop() {
|
public void stop() {
|
||||||
stopped = true;
|
stopped = true;
|
||||||
|
|
||||||
|
if (responseTemplate != null) {
|
||||||
|
responseTemplate.unsubscribe();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (requestTemplate != null) {
|
||||||
|
requestTemplate.stop();
|
||||||
|
}
|
||||||
|
|
||||||
if (internalExecutor) {
|
if (internalExecutor) {
|
||||||
executor.shutdownNow();
|
executor.shutdownNow();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,12 +18,12 @@ package org.thingsboard.server.queue.common;
|
|||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.kafka.common.errors.InterruptException;
|
import org.apache.kafka.common.errors.InterruptException;
|
||||||
|
import org.thingsboard.server.common.msg.queue.TopicPartitionInfo;
|
||||||
import org.thingsboard.server.queue.TbQueueConsumer;
|
import org.thingsboard.server.queue.TbQueueConsumer;
|
||||||
import org.thingsboard.server.queue.TbQueueHandler;
|
import org.thingsboard.server.queue.TbQueueHandler;
|
||||||
import org.thingsboard.server.queue.TbQueueMsg;
|
import org.thingsboard.server.queue.TbQueueMsg;
|
||||||
import org.thingsboard.server.queue.TbQueueProducer;
|
import org.thingsboard.server.queue.TbQueueProducer;
|
||||||
import org.thingsboard.server.queue.TbQueueResponseTemplate;
|
import org.thingsboard.server.queue.TbQueueResponseTemplate;
|
||||||
import org.thingsboard.server.common.msg.queue.TopicPartitionInfo;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
@ -87,6 +87,10 @@ public class DefaultTbQueueResponseTemplate<Request extends TbQueueMsg, Response
|
|||||||
}
|
}
|
||||||
List<Request> requests = requestTemplate.poll(pollInterval);
|
List<Request> requests = requestTemplate.poll(pollInterval);
|
||||||
|
|
||||||
|
if (requests.isEmpty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
requests.forEach(request -> {
|
requests.forEach(request -> {
|
||||||
long currentTime = System.currentTimeMillis();
|
long currentTime = System.currentTimeMillis();
|
||||||
long requestTime = bytesToLong(request.getHeaders().get(REQUEST_TIME));
|
long requestTime = bytesToLong(request.getHeaders().get(REQUEST_TIME));
|
||||||
@ -147,6 +151,12 @@ public class DefaultTbQueueResponseTemplate<Request extends TbQueueMsg, Response
|
|||||||
|
|
||||||
public void stop() {
|
public void stop() {
|
||||||
stopped = true;
|
stopped = true;
|
||||||
|
if (requestTemplate != null) {
|
||||||
|
requestTemplate.unsubscribe();
|
||||||
|
}
|
||||||
|
if (responseTemplate != null) {
|
||||||
|
responseTemplate.stop();
|
||||||
|
}
|
||||||
if (timeoutExecutor != null) {
|
if (timeoutExecutor != null) {
|
||||||
timeoutExecutor.shutdownNow();
|
timeoutExecutor.shutdownNow();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -22,9 +22,9 @@ 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.common.msg.queue.TopicPartitionInfo;
|
||||||
import org.thingsboard.server.queue.TbQueueConsumer;
|
import org.thingsboard.server.queue.TbQueueConsumer;
|
||||||
import org.thingsboard.server.queue.TbQueueMsg;
|
import org.thingsboard.server.queue.TbQueueMsg;
|
||||||
import org.thingsboard.server.common.msg.queue.TopicPartitionInfo;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
@ -96,7 +96,7 @@ public class TBKafkaConsumerTemplate<T extends TbQueueMsg> implements TbQueueCon
|
|||||||
} else {
|
} else {
|
||||||
if (!subscribed) {
|
if (!subscribed) {
|
||||||
List<String> topicNames = partitions.stream().map(TopicPartitionInfo::getFullTopicName).collect(Collectors.toList());
|
List<String> topicNames = partitions.stream().map(TopicPartitionInfo::getFullTopicName).collect(Collectors.toList());
|
||||||
topicNames.forEach(this::createTopicIfNotExists);
|
topicNames.forEach(admin::createTopicIfNotExists);
|
||||||
consumer.subscribe(topicNames);
|
consumer.subscribe(topicNames);
|
||||||
subscribed = true;
|
subscribed = true;
|
||||||
}
|
}
|
||||||
@ -130,7 +130,4 @@ public class TBKafkaConsumerTemplate<T extends TbQueueMsg> implements TbQueueCon
|
|||||||
return decoder.decode(new KafkaTbQueueMsg(record));
|
return decoder.decode(new KafkaTbQueueMsg(record));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createTopicIfNotExists(String topic) {
|
|
||||||
admin.createTopicIfNotExists(topic);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -84,4 +84,9 @@ public class TBKafkaProducerTemplate<T extends TbQueueMsg> implements TbQueuePro
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void stop() {
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -50,4 +50,9 @@ public class InMemoryTbQueueProducer<T extends TbQueueMsg> implements TbQueuePro
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void stop() {
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,127 @@
|
|||||||
|
/**
|
||||||
|
* Copyright © 2016-2020 The Thingsboard Authors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.thingsboard.server.queue.provider;
|
||||||
|
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.thingsboard.server.common.msg.queue.ServiceType;
|
||||||
|
import org.thingsboard.server.gen.transport.TransportProtos;
|
||||||
|
import org.thingsboard.server.queue.TbQueueAdmin;
|
||||||
|
import org.thingsboard.server.queue.TbQueueConsumer;
|
||||||
|
import org.thingsboard.server.queue.TbQueueCoreSettings;
|
||||||
|
import org.thingsboard.server.queue.TbQueueProducer;
|
||||||
|
import org.thingsboard.server.queue.TbQueueRuleEngineSettings;
|
||||||
|
import org.thingsboard.server.queue.TbQueueTransportApiSettings;
|
||||||
|
import org.thingsboard.server.queue.TbQueueTransportNotificationSettings;
|
||||||
|
import org.thingsboard.server.queue.common.TbProtoQueueMsg;
|
||||||
|
import org.thingsboard.server.queue.discovery.PartitionService;
|
||||||
|
import org.thingsboard.server.queue.discovery.TbServiceInfoProvider;
|
||||||
|
import org.thingsboard.server.queue.sqs.TbAwsSqsAdmin;
|
||||||
|
import org.thingsboard.server.queue.sqs.TbAwsSqsConsumerTemplate;
|
||||||
|
import org.thingsboard.server.queue.sqs.TbAwsSqsProducerTemplate;
|
||||||
|
import org.thingsboard.server.queue.sqs.TbAwsSqsSettings;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
@ConditionalOnExpression("'${queue.type:null}'=='aws-sqs' && '${service.type:null}'=='monolith'")
|
||||||
|
public class AwsSqsMonolithQueueProvider implements TbCoreQueueProvider, TbRuleEngineQueueProvider {
|
||||||
|
|
||||||
|
private final PartitionService partitionService;
|
||||||
|
private final TbQueueCoreSettings coreSettings;
|
||||||
|
private final TbServiceInfoProvider serviceInfoProvider;
|
||||||
|
private final TbQueueRuleEngineSettings ruleEngineSettings;
|
||||||
|
private final TbQueueTransportApiSettings transportApiSettings;
|
||||||
|
private final TbQueueTransportNotificationSettings transportNotificationSettings;
|
||||||
|
private final TbAwsSqsSettings sqsSettings;
|
||||||
|
private final TbQueueAdmin admin;
|
||||||
|
|
||||||
|
public AwsSqsMonolithQueueProvider(PartitionService partitionService, TbQueueCoreSettings coreSettings,
|
||||||
|
TbQueueRuleEngineSettings ruleEngineSettings,
|
||||||
|
TbServiceInfoProvider serviceInfoProvider,
|
||||||
|
TbQueueTransportApiSettings transportApiSettings,
|
||||||
|
TbQueueTransportNotificationSettings transportNotificationSettings,
|
||||||
|
TbAwsSqsSettings sqsSettings) {
|
||||||
|
this.partitionService = partitionService;
|
||||||
|
this.coreSettings = coreSettings;
|
||||||
|
this.serviceInfoProvider = serviceInfoProvider;
|
||||||
|
this.ruleEngineSettings = ruleEngineSettings;
|
||||||
|
this.transportApiSettings = transportApiSettings;
|
||||||
|
this.transportNotificationSettings = transportNotificationSettings;
|
||||||
|
this.sqsSettings = sqsSettings;
|
||||||
|
admin = new TbAwsSqsAdmin(sqsSettings);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TbQueueProducer<TbProtoQueueMsg<TransportProtos.ToTransportMsg>> getTransportNotificationsMsgProducer() {
|
||||||
|
return new TbAwsSqsProducerTemplate<>(admin, sqsSettings, transportNotificationSettings.getNotificationsTopic());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TbQueueProducer<TbProtoQueueMsg<TransportProtos.ToRuleEngineMsg>> getRuleEngineMsgProducer() {
|
||||||
|
return new TbAwsSqsProducerTemplate<>(admin, sqsSettings, ruleEngineSettings.getTopic());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TbQueueProducer<TbProtoQueueMsg<TransportProtos.ToRuleEngineNotificationMsg>> getRuleEngineNotificationsMsgProducer() {
|
||||||
|
return new TbAwsSqsProducerTemplate<>(admin, sqsSettings, ruleEngineSettings.getTopic());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TbQueueProducer<TbProtoQueueMsg<TransportProtos.ToCoreMsg>> getTbCoreMsgProducer() {
|
||||||
|
return new TbAwsSqsProducerTemplate<>(admin, sqsSettings, coreSettings.getTopic());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TbQueueProducer<TbProtoQueueMsg<TransportProtos.ToCoreNotificationMsg>> getTbCoreNotificationsMsgProducer() {
|
||||||
|
return new TbAwsSqsProducerTemplate<>(admin, sqsSettings, coreSettings.getTopic());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TbQueueConsumer<TbProtoQueueMsg<TransportProtos.ToRuleEngineMsg>> getToRuleEngineMsgConsumer() {
|
||||||
|
return new TbAwsSqsConsumerTemplate<>(admin, sqsSettings, ruleEngineSettings.getTopic(),
|
||||||
|
msg -> new TbProtoQueueMsg<>(msg.getKey(), TransportProtos.ToRuleEngineMsg.parseFrom(msg.getData()), msg.getHeaders()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TbQueueConsumer<TbProtoQueueMsg<TransportProtos.ToRuleEngineNotificationMsg>> getToRuleEngineNotificationsMsgConsumer() {
|
||||||
|
return new TbAwsSqsConsumerTemplate<>(admin, sqsSettings,
|
||||||
|
partitionService.getNotificationsTopic(ServiceType.TB_RULE_ENGINE, serviceInfoProvider.getServiceId()).getFullTopicName(),
|
||||||
|
msg -> new TbProtoQueueMsg<>(msg.getKey(), TransportProtos.ToRuleEngineNotificationMsg.parseFrom(msg.getData()), msg.getHeaders()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TbQueueConsumer<TbProtoQueueMsg<TransportProtos.ToCoreMsg>> getToCoreMsgConsumer() {
|
||||||
|
return new TbAwsSqsConsumerTemplate<>(admin, sqsSettings, coreSettings.getTopic(),
|
||||||
|
msg -> new TbProtoQueueMsg<>(msg.getKey(), TransportProtos.ToCoreMsg.parseFrom(msg.getData()), msg.getHeaders()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TbQueueConsumer<TbProtoQueueMsg<TransportProtos.ToCoreNotificationMsg>> getToCoreNotificationsMsgConsumer() {
|
||||||
|
return new TbAwsSqsConsumerTemplate<>(admin, sqsSettings,
|
||||||
|
partitionService.getNotificationsTopic(ServiceType.TB_CORE, serviceInfoProvider.getServiceId()).getFullTopicName(),
|
||||||
|
msg -> new TbProtoQueueMsg<>(msg.getKey(), TransportProtos.ToCoreNotificationMsg.parseFrom(msg.getData()), msg.getHeaders()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TbQueueConsumer<TbProtoQueueMsg<TransportProtos.TransportApiRequestMsg>> getTransportApiRequestConsumer() {
|
||||||
|
return new TbAwsSqsConsumerTemplate<>(admin, sqsSettings, transportApiSettings.getRequestsTopic(),
|
||||||
|
msg -> new TbProtoQueueMsg<>(msg.getKey(), TransportProtos.TransportApiRequestMsg.parseFrom(msg.getData()), msg.getHeaders()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TbQueueProducer<TbProtoQueueMsg<TransportProtos.TransportApiResponseMsg>> getTransportApiResponseProducer() {
|
||||||
|
return new TbAwsSqsProducerTemplate<>(admin, sqsSettings, transportApiSettings.getResponsesTopic());
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,117 @@
|
|||||||
|
/**
|
||||||
|
* 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.queue.provider;
|
||||||
|
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.thingsboard.server.common.msg.queue.ServiceType;
|
||||||
|
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.queue.TbQueueAdmin;
|
||||||
|
import org.thingsboard.server.queue.TbQueueConsumer;
|
||||||
|
import org.thingsboard.server.queue.TbQueueCoreSettings;
|
||||||
|
import org.thingsboard.server.queue.TbQueueProducer;
|
||||||
|
import org.thingsboard.server.queue.TbQueueRuleEngineSettings;
|
||||||
|
import org.thingsboard.server.queue.TbQueueTransportApiSettings;
|
||||||
|
import org.thingsboard.server.queue.common.TbProtoQueueMsg;
|
||||||
|
import org.thingsboard.server.queue.discovery.PartitionService;
|
||||||
|
import org.thingsboard.server.queue.discovery.TbServiceInfoProvider;
|
||||||
|
import org.thingsboard.server.queue.sqs.TbAwsSqsAdmin;
|
||||||
|
import org.thingsboard.server.queue.sqs.TbAwsSqsConsumerTemplate;
|
||||||
|
import org.thingsboard.server.queue.sqs.TbAwsSqsProducerTemplate;
|
||||||
|
import org.thingsboard.server.queue.sqs.TbAwsSqsSettings;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
@ConditionalOnExpression("'${queue.type:null}'=='aws-sqs' && '${service.type:null}'=='tb-core'")
|
||||||
|
public class AwsSqsTbCoreQueueProvider implements TbCoreQueueProvider {
|
||||||
|
|
||||||
|
private final TbAwsSqsSettings sqsSettings;
|
||||||
|
private final TbQueueRuleEngineSettings ruleEngineSettings;
|
||||||
|
private final TbQueueCoreSettings coreSettings;
|
||||||
|
private final TbQueueTransportApiSettings transportApiSettings;
|
||||||
|
private final PartitionService partitionService;
|
||||||
|
private final TbServiceInfoProvider serviceInfoProvider;
|
||||||
|
|
||||||
|
|
||||||
|
private final TbQueueAdmin admin;
|
||||||
|
|
||||||
|
public AwsSqsTbCoreQueueProvider(TbAwsSqsSettings sqsSettings,
|
||||||
|
TbQueueCoreSettings coreSettings,
|
||||||
|
TbQueueTransportApiSettings transportApiSettings,
|
||||||
|
TbQueueRuleEngineSettings ruleEngineSettings,
|
||||||
|
PartitionService partitionService,
|
||||||
|
TbServiceInfoProvider serviceInfoProvider) {
|
||||||
|
this.sqsSettings = sqsSettings;
|
||||||
|
this.coreSettings = coreSettings;
|
||||||
|
this.transportApiSettings = transportApiSettings;
|
||||||
|
this.ruleEngineSettings = ruleEngineSettings;
|
||||||
|
this.partitionService = partitionService;
|
||||||
|
this.serviceInfoProvider = serviceInfoProvider;
|
||||||
|
this.admin = new TbAwsSqsAdmin(sqsSettings);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TbQueueProducer<TbProtoQueueMsg<ToTransportMsg>> getTransportNotificationsMsgProducer() {
|
||||||
|
return new TbAwsSqsProducerTemplate<>(admin, sqsSettings, coreSettings.getTopic());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TbQueueProducer<TbProtoQueueMsg<ToRuleEngineMsg>> getRuleEngineMsgProducer() {
|
||||||
|
return new TbAwsSqsProducerTemplate<>(admin, sqsSettings, coreSettings.getTopic());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TbQueueProducer<TbProtoQueueMsg<TransportProtos.ToRuleEngineNotificationMsg>> getRuleEngineNotificationsMsgProducer() {
|
||||||
|
return new TbAwsSqsProducerTemplate<>(admin, sqsSettings, ruleEngineSettings.getTopic());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TbQueueProducer<TbProtoQueueMsg<ToCoreMsg>> getTbCoreMsgProducer() {
|
||||||
|
return new TbAwsSqsProducerTemplate<>(admin, sqsSettings, coreSettings.getTopic());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TbQueueProducer<TbProtoQueueMsg<TransportProtos.ToCoreNotificationMsg>> getTbCoreNotificationsMsgProducer() {
|
||||||
|
return new TbAwsSqsProducerTemplate<>(admin, sqsSettings, coreSettings.getTopic());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TbQueueConsumer<TbProtoQueueMsg<ToCoreMsg>> getToCoreMsgConsumer() {
|
||||||
|
return new TbAwsSqsConsumerTemplate<>(admin, sqsSettings, coreSettings.getTopic(),
|
||||||
|
msg -> new TbProtoQueueMsg<>(msg.getKey(), ToCoreMsg.parseFrom(msg.getData()), msg.getHeaders()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TbQueueConsumer<TbProtoQueueMsg<TransportProtos.ToCoreNotificationMsg>> getToCoreNotificationsMsgConsumer() {
|
||||||
|
return new TbAwsSqsConsumerTemplate<>(admin, sqsSettings,
|
||||||
|
partitionService.getNotificationsTopic(ServiceType.TB_CORE, serviceInfoProvider.getServiceId()).getFullTopicName(),
|
||||||
|
msg -> new TbProtoQueueMsg<>(msg.getKey(), TransportProtos.ToCoreNotificationMsg.parseFrom(msg.getData()), msg.getHeaders()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TbQueueConsumer<TbProtoQueueMsg<TransportApiRequestMsg>> getTransportApiRequestConsumer() {
|
||||||
|
return new TbAwsSqsConsumerTemplate<>(admin, sqsSettings, transportApiSettings.getRequestsTopic(), msg -> new TbProtoQueueMsg<>(msg.getKey(), TransportApiRequestMsg.parseFrom(msg.getData()), msg.getHeaders()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TbQueueProducer<TbProtoQueueMsg<TransportApiResponseMsg>> getTransportApiResponseProducer() {
|
||||||
|
return new TbAwsSqsProducerTemplate<>(admin, sqsSettings, coreSettings.getTopic());
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,97 @@
|
|||||||
|
/**
|
||||||
|
* 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.queue.provider;
|
||||||
|
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.thingsboard.server.common.msg.queue.ServiceType;
|
||||||
|
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.queue.TbQueueAdmin;
|
||||||
|
import org.thingsboard.server.queue.TbQueueConsumer;
|
||||||
|
import org.thingsboard.server.queue.TbQueueCoreSettings;
|
||||||
|
import org.thingsboard.server.queue.TbQueueProducer;
|
||||||
|
import org.thingsboard.server.queue.TbQueueRuleEngineSettings;
|
||||||
|
import org.thingsboard.server.queue.common.TbProtoQueueMsg;
|
||||||
|
import org.thingsboard.server.queue.discovery.PartitionService;
|
||||||
|
import org.thingsboard.server.queue.discovery.TbServiceInfoProvider;
|
||||||
|
import org.thingsboard.server.queue.sqs.TbAwsSqsAdmin;
|
||||||
|
import org.thingsboard.server.queue.sqs.TbAwsSqsConsumerTemplate;
|
||||||
|
import org.thingsboard.server.queue.sqs.TbAwsSqsProducerTemplate;
|
||||||
|
import org.thingsboard.server.queue.sqs.TbAwsSqsSettings;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
@ConditionalOnExpression("'${queue.type:null}'=='aws-sqs' && '${service.type:null}'=='tb-rule-engine'")
|
||||||
|
public class AwsSqsTbRuleEngineQueueProvider implements TbRuleEngineQueueProvider {
|
||||||
|
|
||||||
|
private final PartitionService partitionService;
|
||||||
|
private final TbQueueCoreSettings coreSettings;
|
||||||
|
private final TbServiceInfoProvider serviceInfoProvider;
|
||||||
|
private final TbQueueRuleEngineSettings ruleEngineSettings;
|
||||||
|
private final TbAwsSqsSettings sqsSettings;
|
||||||
|
private final TbQueueAdmin admin;
|
||||||
|
|
||||||
|
public AwsSqsTbRuleEngineQueueProvider(PartitionService partitionService, TbQueueCoreSettings coreSettings,
|
||||||
|
TbQueueRuleEngineSettings ruleEngineSettings,
|
||||||
|
TbServiceInfoProvider serviceInfoProvider,
|
||||||
|
TbAwsSqsSettings sqsSettings) {
|
||||||
|
this.partitionService = partitionService;
|
||||||
|
this.coreSettings = coreSettings;
|
||||||
|
this.serviceInfoProvider = serviceInfoProvider;
|
||||||
|
this.ruleEngineSettings = ruleEngineSettings;
|
||||||
|
this.sqsSettings = sqsSettings;
|
||||||
|
admin = new TbAwsSqsAdmin(sqsSettings);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TbQueueProducer<TbProtoQueueMsg<ToTransportMsg>> getTransportNotificationsMsgProducer() {
|
||||||
|
return new TbAwsSqsProducerTemplate<>(admin, sqsSettings, coreSettings.getTopic());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TbQueueProducer<TbProtoQueueMsg<ToRuleEngineMsg>> getRuleEngineMsgProducer() {
|
||||||
|
return new TbAwsSqsProducerTemplate<>(admin, sqsSettings, coreSettings.getTopic());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TbQueueProducer<TbProtoQueueMsg<TransportProtos.ToRuleEngineNotificationMsg>> getRuleEngineNotificationsMsgProducer() {
|
||||||
|
return new TbAwsSqsProducerTemplate<>(admin, sqsSettings, ruleEngineSettings.getTopic());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TbQueueProducer<TbProtoQueueMsg<ToCoreMsg>> getTbCoreMsgProducer() {
|
||||||
|
return new TbAwsSqsProducerTemplate<>(admin, sqsSettings, coreSettings.getTopic());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TbQueueProducer<TbProtoQueueMsg<TransportProtos.ToCoreNotificationMsg>> getTbCoreNotificationsMsgProducer() {
|
||||||
|
return new TbAwsSqsProducerTemplate<>(admin, sqsSettings, coreSettings.getTopic());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TbQueueConsumer<TbProtoQueueMsg<ToRuleEngineMsg>> getToRuleEngineMsgConsumer() {
|
||||||
|
return new TbAwsSqsConsumerTemplate<>(admin, sqsSettings, ruleEngineSettings.getTopic(), msg -> new TbProtoQueueMsg<>(msg.getKey(), ToRuleEngineMsg.parseFrom(msg.getData()), msg.getHeaders()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TbQueueConsumer<TbProtoQueueMsg<TransportProtos.ToRuleEngineNotificationMsg>> getToRuleEngineNotificationsMsgConsumer() {
|
||||||
|
return new TbAwsSqsConsumerTemplate<>(admin, sqsSettings,
|
||||||
|
partitionService.getNotificationsTopic(ServiceType.TB_RULE_ENGINE, serviceInfoProvider.getServiceId()).getFullTopicName(),
|
||||||
|
msg -> new TbProtoQueueMsg<>(msg.getKey(), TransportProtos.ToRuleEngineNotificationMsg.parseFrom(msg.getData()), msg.getHeaders()));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,93 @@
|
|||||||
|
/**
|
||||||
|
* 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.queue.provider;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.thingsboard.server.gen.transport.TransportProtos;
|
||||||
|
import org.thingsboard.server.queue.TbQueueAdmin;
|
||||||
|
import org.thingsboard.server.queue.TbQueueConsumer;
|
||||||
|
import org.thingsboard.server.queue.TbQueueProducer;
|
||||||
|
import org.thingsboard.server.queue.TbQueueRequestTemplate;
|
||||||
|
import org.thingsboard.server.queue.TbQueueTransportApiSettings;
|
||||||
|
import org.thingsboard.server.queue.TbQueueTransportNotificationSettings;
|
||||||
|
import org.thingsboard.server.queue.common.DefaultTbQueueRequestTemplate;
|
||||||
|
import org.thingsboard.server.queue.common.TbProtoQueueMsg;
|
||||||
|
import org.thingsboard.server.queue.discovery.TbServiceInfoProvider;
|
||||||
|
import org.thingsboard.server.queue.sqs.TbAwsSqsAdmin;
|
||||||
|
import org.thingsboard.server.queue.sqs.TbAwsSqsConsumerTemplate;
|
||||||
|
import org.thingsboard.server.queue.sqs.TbAwsSqsProducerTemplate;
|
||||||
|
import org.thingsboard.server.queue.sqs.TbAwsSqsSettings;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
@ConditionalOnExpression("'${queue.type:null}'=='aws-sqs' && ('${service.type:null}'=='monolith' || '${service.type:null}'=='tb-transport')")
|
||||||
|
@Slf4j
|
||||||
|
public class AwsSqsTransportQueueProvider implements TbTransportQueueProvider {
|
||||||
|
private final TbQueueTransportApiSettings transportApiSettings;
|
||||||
|
private final TbQueueTransportNotificationSettings transportNotificationSettings;
|
||||||
|
private final TbAwsSqsSettings sqsSettings;
|
||||||
|
private final TbQueueAdmin admin;
|
||||||
|
private final TbServiceInfoProvider serviceInfoProvider;
|
||||||
|
|
||||||
|
public AwsSqsTransportQueueProvider(TbQueueTransportApiSettings transportApiSettings,
|
||||||
|
TbQueueTransportNotificationSettings transportNotificationSettings,
|
||||||
|
TbAwsSqsSettings sqsSettings,
|
||||||
|
TbServiceInfoProvider serviceInfoProvider) {
|
||||||
|
this.transportApiSettings = transportApiSettings;
|
||||||
|
this.transportNotificationSettings = transportNotificationSettings;
|
||||||
|
this.sqsSettings = sqsSettings;
|
||||||
|
admin = new TbAwsSqsAdmin(sqsSettings);
|
||||||
|
this.serviceInfoProvider = serviceInfoProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TbQueueRequestTemplate<TbProtoQueueMsg<TransportProtos.TransportApiRequestMsg>, TbProtoQueueMsg<TransportProtos.TransportApiResponseMsg>> getTransportApiRequestTemplate() {
|
||||||
|
TbAwsSqsProducerTemplate<TbProtoQueueMsg<TransportProtos.TransportApiRequestMsg>> producerTemplate =
|
||||||
|
new TbAwsSqsProducerTemplate<>(admin, sqsSettings, transportApiSettings.getRequestsTopic());
|
||||||
|
|
||||||
|
TbAwsSqsConsumerTemplate<TbProtoQueueMsg<TransportProtos.TransportApiResponseMsg>> consumerTemplate =
|
||||||
|
new TbAwsSqsConsumerTemplate<>(admin, sqsSettings,
|
||||||
|
transportApiSettings.getResponsesTopic() + "_" + serviceInfoProvider.getServiceId(),
|
||||||
|
msg -> new TbProtoQueueMsg<>(msg.getKey(), TransportProtos.TransportApiResponseMsg.parseFrom(msg.getData()), msg.getHeaders()));
|
||||||
|
|
||||||
|
DefaultTbQueueRequestTemplate.DefaultTbQueueRequestTemplateBuilder
|
||||||
|
<TbProtoQueueMsg<TransportProtos.TransportApiRequestMsg>, TbProtoQueueMsg<TransportProtos.TransportApiResponseMsg>> templateBuilder = DefaultTbQueueRequestTemplate.builder();
|
||||||
|
templateBuilder.queueAdmin(admin);
|
||||||
|
templateBuilder.requestTemplate(producerTemplate);
|
||||||
|
templateBuilder.responseTemplate(consumerTemplate);
|
||||||
|
templateBuilder.maxPendingRequests(transportApiSettings.getMaxPendingRequests());
|
||||||
|
templateBuilder.maxRequestTimeout(transportApiSettings.getMaxRequestsTimeout());
|
||||||
|
templateBuilder.pollInterval(transportApiSettings.getResponsePollInterval());
|
||||||
|
return templateBuilder.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TbQueueProducer<TbProtoQueueMsg<TransportProtos.ToRuleEngineMsg>> getRuleEngineMsgProducer() {
|
||||||
|
return new TbAwsSqsProducerTemplate<>(admin, sqsSettings, transportApiSettings.getRequestsTopic());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TbQueueProducer<TbProtoQueueMsg<TransportProtos.ToCoreMsg>> getTbCoreMsgProducer() {
|
||||||
|
return new TbAwsSqsProducerTemplate<>(admin, sqsSettings, transportApiSettings.getRequestsTopic());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TbQueueConsumer<TbProtoQueueMsg<TransportProtos.ToTransportMsg>> getTransportNotificationsConsumer() {
|
||||||
|
return new TbAwsSqsConsumerTemplate<>(admin, sqsSettings, transportNotificationSettings.getNotificationsTopic() + "_" + serviceInfoProvider.getServiceId(),
|
||||||
|
msg -> new TbProtoQueueMsg<>(msg.getKey(), TransportProtos.ToTransportMsg.parseFrom(msg.getData()), msg.getHeaders()));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +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.queue.sqs;
|
||||||
|
|
||||||
|
import com.amazonaws.http.SdkHttpMetadata;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import org.thingsboard.server.queue.TbQueueMsgMetadata;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class AwsSqsTbQueueMsgMetadata implements TbQueueMsgMetadata {
|
||||||
|
|
||||||
|
private final SdkHttpMetadata metadata;
|
||||||
|
}
|
||||||
@ -0,0 +1,65 @@
|
|||||||
|
/**
|
||||||
|
* 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.queue.sqs;
|
||||||
|
|
||||||
|
import com.amazonaws.auth.AWSCredentials;
|
||||||
|
import com.amazonaws.auth.AWSStaticCredentialsProvider;
|
||||||
|
import com.amazonaws.auth.BasicAWSCredentials;
|
||||||
|
import com.amazonaws.services.sqs.AmazonSQS;
|
||||||
|
import com.amazonaws.services.sqs.AmazonSQSClientBuilder;
|
||||||
|
import com.amazonaws.services.sqs.model.CreateQueueRequest;
|
||||||
|
import com.amazonaws.services.sqs.model.QueueAttributeName;
|
||||||
|
import org.thingsboard.server.queue.TbQueueAdmin;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class TbAwsSqsAdmin implements TbQueueAdmin {
|
||||||
|
|
||||||
|
private final TbAwsSqsSettings sqsSettings;
|
||||||
|
private final Map<String, String> attributes = new HashMap<>();
|
||||||
|
private final AWSStaticCredentialsProvider credProvider;
|
||||||
|
|
||||||
|
public TbAwsSqsAdmin(TbAwsSqsSettings sqsSettings) {
|
||||||
|
this.sqsSettings = sqsSettings;
|
||||||
|
|
||||||
|
AWSCredentials awsCredentials = new BasicAWSCredentials(sqsSettings.getAccessKeyId(), sqsSettings.getSecretAccessKey());
|
||||||
|
this.credProvider = new AWSStaticCredentialsProvider(awsCredentials);
|
||||||
|
|
||||||
|
attributes.put("FifoQueue", "true");
|
||||||
|
attributes.put("ContentBasedDeduplication", "true");
|
||||||
|
attributes.put(QueueAttributeName.VisibilityTimeout.toString(), sqsSettings.getVisibilityTimeout());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void createTopicIfNotExists(String topic) {
|
||||||
|
AmazonSQS sqsClient = AmazonSQSClientBuilder.standard()
|
||||||
|
.withCredentials(credProvider)
|
||||||
|
.withRegion(sqsSettings.getRegion())
|
||||||
|
.build();
|
||||||
|
|
||||||
|
final CreateQueueRequest createQueueRequest =
|
||||||
|
new CreateQueueRequest(topic.replaceAll("\\.", "_") + ".fifo")
|
||||||
|
.withAttributes(attributes);
|
||||||
|
try {
|
||||||
|
sqsClient.createQueue(createQueueRequest);
|
||||||
|
} finally {
|
||||||
|
if (sqsClient != null) {
|
||||||
|
sqsClient.shutdown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,239 @@
|
|||||||
|
/**
|
||||||
|
* 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.queue.sqs;
|
||||||
|
|
||||||
|
import com.amazonaws.auth.AWSCredentials;
|
||||||
|
import com.amazonaws.auth.AWSStaticCredentialsProvider;
|
||||||
|
import com.amazonaws.auth.BasicAWSCredentials;
|
||||||
|
import com.amazonaws.services.sqs.AmazonSQS;
|
||||||
|
import com.amazonaws.services.sqs.AmazonSQSClientBuilder;
|
||||||
|
import com.amazonaws.services.sqs.model.DeleteMessageBatchRequestEntry;
|
||||||
|
import com.amazonaws.services.sqs.model.Message;
|
||||||
|
import com.amazonaws.services.sqs.model.ReceiveMessageRequest;
|
||||||
|
import com.google.common.reflect.TypeToken;
|
||||||
|
import com.google.common.util.concurrent.Futures;
|
||||||
|
import com.google.common.util.concurrent.ListenableFuture;
|
||||||
|
import com.google.common.util.concurrent.ListeningExecutorService;
|
||||||
|
import com.google.common.util.concurrent.MoreExecutors;
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.protobuf.InvalidProtocolBufferException;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.util.CollectionUtils;
|
||||||
|
import org.thingsboard.server.common.msg.queue.TopicPartitionInfo;
|
||||||
|
import org.thingsboard.server.queue.TbQueueAdmin;
|
||||||
|
import org.thingsboard.server.queue.TbQueueConsumer;
|
||||||
|
import org.thingsboard.server.queue.TbQueueMsg;
|
||||||
|
import org.thingsboard.server.queue.TbQueueMsgDecoder;
|
||||||
|
import org.thingsboard.server.queue.TbQueueMsgHeaders;
|
||||||
|
import org.thingsboard.server.queue.common.DefaultTbQueueMsgHeaders;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
public class TbAwsSqsConsumerTemplate<T extends TbQueueMsg> implements TbQueueConsumer<T> {
|
||||||
|
|
||||||
|
private static final int MAX_NUM_MSGS = 10;
|
||||||
|
|
||||||
|
private final Gson gson = new Gson();
|
||||||
|
private final TbQueueAdmin admin;
|
||||||
|
private final AmazonSQS sqsClient;
|
||||||
|
private final String topic;
|
||||||
|
private final TbQueueMsgDecoder<T> decoder;
|
||||||
|
private final TbAwsSqsSettings sqsSettings;
|
||||||
|
|
||||||
|
private final List<AwsSqsMsgWrapper> pendingMessages = new CopyOnWriteArrayList<>();
|
||||||
|
private volatile Set<String> queueUrls;
|
||||||
|
private volatile Set<TopicPartitionInfo> partitions;
|
||||||
|
private ListeningExecutorService consumerExecutor;
|
||||||
|
private volatile boolean subscribed;
|
||||||
|
private volatile boolean stopped = false;
|
||||||
|
|
||||||
|
public TbAwsSqsConsumerTemplate(TbQueueAdmin admin, TbAwsSqsSettings sqsSettings, String topic, TbQueueMsgDecoder<T> decoder) {
|
||||||
|
this.admin = admin;
|
||||||
|
this.decoder = decoder;
|
||||||
|
this.topic = topic;
|
||||||
|
this.sqsSettings = sqsSettings;
|
||||||
|
|
||||||
|
AWSCredentials awsCredentials = new BasicAWSCredentials(sqsSettings.getAccessKeyId(), sqsSettings.getSecretAccessKey());
|
||||||
|
AWSStaticCredentialsProvider credProvider = new AWSStaticCredentialsProvider(awsCredentials);
|
||||||
|
|
||||||
|
this.sqsClient = AmazonSQSClientBuilder.standard()
|
||||||
|
.withCredentials(credProvider)
|
||||||
|
.withRegion(sqsSettings.getRegion())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getTopic() {
|
||||||
|
return topic;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void subscribe() {
|
||||||
|
partitions = Collections.singleton(new TopicPartitionInfo(topic, null, null, true));
|
||||||
|
subscribed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void subscribe(Set<TopicPartitionInfo> partitions) {
|
||||||
|
this.partitions = partitions;
|
||||||
|
subscribed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void unsubscribe() {
|
||||||
|
stopped = true;
|
||||||
|
|
||||||
|
if (sqsClient != null) {
|
||||||
|
sqsClient.shutdown();
|
||||||
|
}
|
||||||
|
if (consumerExecutor != null) {
|
||||||
|
consumerExecutor.shutdownNow();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<T> poll(long durationInMillis) {
|
||||||
|
if (!subscribed && partitions == null) {
|
||||||
|
try {
|
||||||
|
Thread.sleep(durationInMillis);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
log.debug("Failed to await subscription", e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!subscribed) {
|
||||||
|
List<String> topicNames = partitions.stream().map(TopicPartitionInfo::getFullTopicName).collect(Collectors.toList());
|
||||||
|
queueUrls = topicNames.stream().map(this::getQueueUrl).collect(Collectors.toSet());
|
||||||
|
consumerExecutor = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(queueUrls.size() * sqsSettings.getThreadsPerTopic() + 1));
|
||||||
|
subscribed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pendingMessages.isEmpty()) {
|
||||||
|
log.warn("Present {} non committed messages.", pendingMessages.size());
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
List<ListenableFuture<List<Message>>> futureList = queueUrls
|
||||||
|
.stream()
|
||||||
|
.map(url -> poll(url, (int) TimeUnit.MILLISECONDS.toSeconds(durationInMillis)))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
ListenableFuture<List<List<Message>>> futureResult = Futures.allAsList(futureList);
|
||||||
|
try {
|
||||||
|
return futureResult.get().stream()
|
||||||
|
.flatMap(List::stream)
|
||||||
|
.map(msg -> {
|
||||||
|
try {
|
||||||
|
return decode(msg);
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("Failed to decode message: [{}]", msg);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}).filter(Objects::nonNull)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
} catch (InterruptedException | ExecutionException e) {
|
||||||
|
if (stopped) {
|
||||||
|
log.info("[{}] Aws SQS consumer is stopped.", topic);
|
||||||
|
} else {
|
||||||
|
log.error("Failed to pool messages.", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private ListenableFuture<List<Message>> poll(String url, int waitTimeSeconds) {
|
||||||
|
List<ListenableFuture<List<Message>>> result = new ArrayList<>();
|
||||||
|
|
||||||
|
for (int i = 0; i < sqsSettings.getThreadsPerTopic(); i++) {
|
||||||
|
result.add(consumerExecutor.submit(() -> {
|
||||||
|
ReceiveMessageRequest request = new ReceiveMessageRequest();
|
||||||
|
request
|
||||||
|
.withWaitTimeSeconds(waitTimeSeconds)
|
||||||
|
.withMessageAttributeNames("headers")
|
||||||
|
.withQueueUrl(url)
|
||||||
|
.withMaxNumberOfMessages(MAX_NUM_MSGS);
|
||||||
|
return sqsClient.receiveMessage(request).getMessages();
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
return Futures.transform(Futures.allAsList(result), list -> {
|
||||||
|
if (!CollectionUtils.isEmpty(list)) {
|
||||||
|
return list.stream()
|
||||||
|
.flatMap(messageList -> {
|
||||||
|
if (!messageList.isEmpty()) {
|
||||||
|
this.pendingMessages.add(new AwsSqsMsgWrapper(url, messageList));
|
||||||
|
return messageList.stream();
|
||||||
|
}
|
||||||
|
return Stream.empty();
|
||||||
|
})
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
return Collections.emptyList();
|
||||||
|
}, consumerExecutor);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void commit() {
|
||||||
|
pendingMessages.forEach(msg ->
|
||||||
|
consumerExecutor.submit(() -> {
|
||||||
|
List<DeleteMessageBatchRequestEntry> entries = msg.getMessages()
|
||||||
|
.stream()
|
||||||
|
.map(message -> new DeleteMessageBatchRequestEntry(message.getMessageId(), message.getReceiptHandle()))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
sqsClient.deleteMessageBatch(msg.getUrl(), entries);
|
||||||
|
}));
|
||||||
|
|
||||||
|
pendingMessages.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public T decode(Message message) throws InvalidProtocolBufferException {
|
||||||
|
TbAwsSqsMsg msg = gson.fromJson(message.getBody(), TbAwsSqsMsg.class);
|
||||||
|
TbQueueMsgHeaders headers = new DefaultTbQueueMsgHeaders();
|
||||||
|
Map<String, byte[]> headerMap = gson.fromJson(message.getMessageAttributes().get("headers").getStringValue(), new TypeToken<Map<String, byte[]>>() {
|
||||||
|
}.getType());
|
||||||
|
headerMap.forEach(headers::put);
|
||||||
|
msg.setHeaders(headers);
|
||||||
|
return decoder.decode(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
private static class AwsSqsMsgWrapper {
|
||||||
|
private final String url;
|
||||||
|
private final List<Message> messages;
|
||||||
|
|
||||||
|
public AwsSqsMsgWrapper(String url, List<Message> messages) {
|
||||||
|
this.url = url;
|
||||||
|
this.messages = messages;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getQueueUrl(String topic) {
|
||||||
|
admin.createTopicIfNotExists(topic);
|
||||||
|
return sqsClient.getQueueUrl(topic.replaceAll("\\.", "_") + ".fifo").getQueueUrl();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,38 @@
|
|||||||
|
/**
|
||||||
|
* Copyright © 2016-2020 The Thingsboard Authors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.thingsboard.server.queue.sqs;
|
||||||
|
|
||||||
|
import com.google.gson.annotations.Expose;
|
||||||
|
import lombok.Data;
|
||||||
|
import org.thingsboard.server.queue.TbQueueMsg;
|
||||||
|
import org.thingsboard.server.queue.TbQueueMsgHeaders;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class TbAwsSqsMsg implements TbQueueMsg {
|
||||||
|
private final UUID key;
|
||||||
|
private final byte[] data;
|
||||||
|
|
||||||
|
public TbAwsSqsMsg(UUID key, byte[] data) {
|
||||||
|
this.key = key;
|
||||||
|
this.data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Expose(serialize = false, deserialize = false)
|
||||||
|
private TbQueueMsgHeaders headers;
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,127 @@
|
|||||||
|
/**
|
||||||
|
* Copyright © 2016-2020 The Thingsboard Authors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.thingsboard.server.queue.sqs;
|
||||||
|
|
||||||
|
import com.amazonaws.auth.AWSCredentials;
|
||||||
|
import com.amazonaws.auth.AWSStaticCredentialsProvider;
|
||||||
|
import com.amazonaws.auth.BasicAWSCredentials;
|
||||||
|
import com.amazonaws.services.sqs.AmazonSQS;
|
||||||
|
import com.amazonaws.services.sqs.AmazonSQSClientBuilder;
|
||||||
|
import com.amazonaws.services.sqs.model.MessageAttributeValue;
|
||||||
|
import com.amazonaws.services.sqs.model.SendMessageRequest;
|
||||||
|
import com.amazonaws.services.sqs.model.SendMessageResult;
|
||||||
|
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.ListeningExecutorService;
|
||||||
|
import com.google.common.util.concurrent.MoreExecutors;
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.thingsboard.server.common.msg.queue.TopicPartitionInfo;
|
||||||
|
import org.thingsboard.server.queue.TbQueueAdmin;
|
||||||
|
import org.thingsboard.server.queue.TbQueueCallback;
|
||||||
|
import org.thingsboard.server.queue.TbQueueMsg;
|
||||||
|
import org.thingsboard.server.queue.TbQueueProducer;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
public class TbAwsSqsProducerTemplate<T extends TbQueueMsg> implements TbQueueProducer<T> {
|
||||||
|
private final String defaultTopic;
|
||||||
|
private final AmazonSQS sqsClient;
|
||||||
|
private final Gson gson = new Gson();
|
||||||
|
private final Map<String, String> queueUrlMap = new ConcurrentHashMap<>();
|
||||||
|
private final TbQueueAdmin admin;
|
||||||
|
private ListeningExecutorService producerExecutor;
|
||||||
|
|
||||||
|
public TbAwsSqsProducerTemplate(TbQueueAdmin admin, TbAwsSqsSettings sqsSettings, String defaultTopic) {
|
||||||
|
this.admin = admin;
|
||||||
|
this.defaultTopic = defaultTopic;
|
||||||
|
|
||||||
|
AWSCredentials awsCredentials = new BasicAWSCredentials(sqsSettings.getAccessKeyId(), sqsSettings.getSecretAccessKey());
|
||||||
|
AWSStaticCredentialsProvider credProvider = new AWSStaticCredentialsProvider(awsCredentials);
|
||||||
|
|
||||||
|
this.sqsClient = AmazonSQSClientBuilder.standard()
|
||||||
|
.withCredentials(credProvider)
|
||||||
|
.withRegion(sqsSettings.getRegion())
|
||||||
|
.build();
|
||||||
|
|
||||||
|
producerExecutor = MoreExecutors.listeningDecorator(Executors.newCachedThreadPool());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDefaultTopic() {
|
||||||
|
return defaultTopic;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void send(TopicPartitionInfo tpi, T msg, TbQueueCallback callback) {
|
||||||
|
SendMessageRequest sendMsgRequest = new SendMessageRequest();
|
||||||
|
sendMsgRequest.withQueueUrl(getQueueUrl(tpi.getFullTopicName()));
|
||||||
|
sendMsgRequest.withMessageBody(gson.toJson(new TbAwsSqsMsg(msg.getKey(), msg.getData())));
|
||||||
|
|
||||||
|
Map<String, MessageAttributeValue> attributes = new HashMap<>();
|
||||||
|
|
||||||
|
attributes.put("headers", new MessageAttributeValue()
|
||||||
|
.withStringValue(gson.toJson(msg.getHeaders().getData()))
|
||||||
|
.withDataType("String"));
|
||||||
|
|
||||||
|
sendMsgRequest.withMessageAttributes(attributes);
|
||||||
|
sendMsgRequest.withMessageGroupId(msg.getKey().toString());
|
||||||
|
ListenableFuture<SendMessageResult> future = producerExecutor.submit(() -> sqsClient.sendMessage(sendMsgRequest));
|
||||||
|
|
||||||
|
Futures.addCallback(future, new FutureCallback<SendMessageResult>() {
|
||||||
|
@Override
|
||||||
|
public void onSuccess(SendMessageResult result) {
|
||||||
|
if (callback != null) {
|
||||||
|
callback.onSuccess(new AwsSqsTbQueueMsgMetadata(result.getSdkHttpMetadata()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(Throwable t) {
|
||||||
|
if (callback != null) {
|
||||||
|
callback.onFailure(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void stop() {
|
||||||
|
if (producerExecutor != null) {
|
||||||
|
producerExecutor.shutdownNow();
|
||||||
|
}
|
||||||
|
if (sqsClient != null) {
|
||||||
|
sqsClient.shutdown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getQueueUrl(String topic) {
|
||||||
|
return queueUrlMap.computeIfAbsent(topic, k -> {
|
||||||
|
admin.createTopicIfNotExists(topic);
|
||||||
|
return sqsClient.getQueueUrl(topic.replaceAll("\\.", "_") + ".fifo").getQueueUrl();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,44 @@
|
|||||||
|
/**
|
||||||
|
* 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.queue.sqs;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@ConditionalOnExpression("'${queue.type:null}'=='aws-sqs'")
|
||||||
|
@Component
|
||||||
|
@Data
|
||||||
|
public class TbAwsSqsSettings {
|
||||||
|
|
||||||
|
@Value("${queue.aws_sqs.access_key_id}")
|
||||||
|
private String accessKeyId;
|
||||||
|
|
||||||
|
@Value("${queue.aws_sqs.secret_access_key}")
|
||||||
|
private String secretAccessKey;
|
||||||
|
|
||||||
|
@Value("${queue.aws_sqs.region}")
|
||||||
|
private String region;
|
||||||
|
|
||||||
|
@Value("${queue.aws_sqs.threads_per_topic}")
|
||||||
|
private int threadsPerTopic;
|
||||||
|
|
||||||
|
@Value("${queue.aws_sqs.visibility_timeout}")
|
||||||
|
private String visibilityTimeout;
|
||||||
|
}
|
||||||
@ -138,6 +138,9 @@ public class DefaultTransportService implements TransportService {
|
|||||||
while (!stopped) {
|
while (!stopped) {
|
||||||
try {
|
try {
|
||||||
List<TbProtoQueueMsg<ToTransportMsg>> records = transportNotificationsConsumer.poll(notificationsPollDuration);
|
List<TbProtoQueueMsg<ToTransportMsg>> records = transportNotificationsConsumer.poll(notificationsPollDuration);
|
||||||
|
if (records.size() == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
records.forEach(record -> {
|
records.forEach(record -> {
|
||||||
try {
|
try {
|
||||||
ToTransportMsg toTransportMsg = record.getValue();
|
ToTransportMsg toTransportMsg = record.getValue();
|
||||||
@ -170,6 +173,10 @@ public class DefaultTransportService implements TransportService {
|
|||||||
perDeviceLimits.clear();
|
perDeviceLimits.clear();
|
||||||
}
|
}
|
||||||
stopped = true;
|
stopped = true;
|
||||||
|
|
||||||
|
if (transportNotificationsConsumer != null) {
|
||||||
|
transportNotificationsConsumer.unsubscribe();
|
||||||
|
}
|
||||||
if (schedulerExecutor != null) {
|
if (schedulerExecutor != null) {
|
||||||
schedulerExecutor.shutdownNow();
|
schedulerExecutor.shutdownNow();
|
||||||
}
|
}
|
||||||
|
|||||||
6
pom.xml
6
pom.xml
@ -92,6 +92,7 @@
|
|||||||
<fst.version>2.57</fst.version>
|
<fst.version>2.57</fst.version>
|
||||||
<antlr.version>2.7.7</antlr.version>
|
<antlr.version>2.7.7</antlr.version>
|
||||||
<snakeyaml.version>1.23</snakeyaml.version>
|
<snakeyaml.version>1.23</snakeyaml.version>
|
||||||
|
<amazonaws.sqs.version>1.11.747</amazonaws.sqs.version>
|
||||||
<passay.version>1.5.0</passay.version>
|
<passay.version>1.5.0</passay.version>
|
||||||
<ua-parser.version>1.4.3</ua-parser.version>
|
<ua-parser.version>1.4.3</ua-parser.version>
|
||||||
</properties>
|
</properties>
|
||||||
@ -886,6 +887,11 @@
|
|||||||
<artifactId>jts-core</artifactId>
|
<artifactId>jts-core</artifactId>
|
||||||
<version>${jts.version}</version>
|
<version>${jts.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.amazonaws</groupId>
|
||||||
|
<artifactId>aws-java-sdk-sqs</artifactId>
|
||||||
|
<version>${amazonaws.sqs.version}</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.passay</groupId>
|
<groupId>org.passay</groupId>
|
||||||
<artifactId>passay</artifactId>
|
<artifactId>passay</artifactId>
|
||||||
|
|||||||
@ -35,7 +35,7 @@
|
|||||||
<properties>
|
<properties>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
<main.dir>${basedir}/../..</main.dir>
|
<main.dir>${basedir}/../..</main.dir>
|
||||||
<aws.sdk.version>1.11.323</aws.sdk.version>
|
<aws.sdk.version>1.11.747</aws.sdk.version>
|
||||||
<pubsub.client.version>1.83.0</pubsub.client.version>
|
<pubsub.client.version>1.83.0</pubsub.client.version>
|
||||||
<google.common.protos.version>1.16.0</google.common.protos.version>
|
<google.common.protos.version>1.16.0</google.common.protos.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|||||||
@ -63,7 +63,7 @@ transport:
|
|||||||
max_string_value_length: "${JSON_MAX_STRING_VALUE_LENGTH:0}"
|
max_string_value_length: "${JSON_MAX_STRING_VALUE_LENGTH:0}"
|
||||||
|
|
||||||
queue:
|
queue:
|
||||||
type: "${TB_QUEUE_TYPE:kafka}" # kafka or ?
|
type: "${TB_QUEUE_TYPE:kafka}" # kafka or aws-sqs
|
||||||
kafka:
|
kafka:
|
||||||
bootstrap.servers: "${TB_KAFKA_SERVERS:localhost:9092}"
|
bootstrap.servers: "${TB_KAFKA_SERVERS:localhost:9092}"
|
||||||
acks: "${TB_KAFKA_ACKS:all}"
|
acks: "${TB_KAFKA_ACKS:all}"
|
||||||
@ -71,6 +71,10 @@ queue:
|
|||||||
batch.size: "${TB_KAFKA_BATCH_SIZE:16384}"
|
batch.size: "${TB_KAFKA_BATCH_SIZE:16384}"
|
||||||
linger.ms: "${TB_KAFKA_LINGER_MS:1}"
|
linger.ms: "${TB_KAFKA_LINGER_MS:1}"
|
||||||
buffer.memory: "${TB_BUFFER_MEMORY:33554432}"
|
buffer.memory: "${TB_BUFFER_MEMORY:33554432}"
|
||||||
|
aws_sqs:
|
||||||
|
access_key_id: "${TB_QUEUE_AWS_SQS_ACCESS_KEY_ID:YOUR_KEY}"
|
||||||
|
secret_access_key: "${TB_QUEUE_AWS_SQS_SECRET_ACCESS_KEY:YOUR_SECRET}"
|
||||||
|
region: "${TB_QUEUE_AWS_SQS_REGION:YOUR_REGION}"
|
||||||
partitions:
|
partitions:
|
||||||
hash_function_name: "${TB_QUEUE_PARTITIONS_HASH_FUNCTION_NAME:murmur3_128}"
|
hash_function_name: "${TB_QUEUE_PARTITIONS_HASH_FUNCTION_NAME:murmur3_128}"
|
||||||
virtual_nodes_size: "${TB_QUEUE_PARTITIONS_VIRTUAL_NODES_SIZE:16}"
|
virtual_nodes_size: "${TB_QUEUE_PARTITIONS_VIRTUAL_NODES_SIZE:16}"
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user