Browse Source

Refactoring GrpsSession

pull/11924/head
Andrii Landiak 2 years ago
parent
commit
30d5176406
  1. 34
      application/src/main/java/org/thingsboard/server/service/edge/EdgeEventSourcingListener.java
  2. 6
      application/src/main/java/org/thingsboard/server/service/edge/rpc/AbstractEdgeGrpcSession.java
  3. 62
      application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcService.java
  4. 7
      application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcSession.java
  5. 120
      application/src/main/java/org/thingsboard/server/service/edge/rpc/KafkaEdgeGrpcSession.java
  6. 7
      application/src/main/java/org/thingsboard/server/service/edge/rpc/PostgresEdgeGrpcSession.java
  7. 37
      application/src/main/java/org/thingsboard/server/service/entitiy/EntityStateSourcingListener.java

34
application/src/main/java/org/thingsboard/server/service/edge/EdgeEventSourcingListener.java

@ -20,10 +20,6 @@ import com.fasterxml.jackson.databind.node.ObjectNode;
import jakarta.annotation.PostConstruct; import jakarta.annotation.PostConstruct;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; 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.ConditionalOnExpression;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.transaction.event.TransactionalEventListener; import org.springframework.transaction.event.TransactionalEventListener;
import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.common.util.JacksonUtil;
@ -41,7 +37,6 @@ import org.thingsboard.server.common.data.domain.Domain;
import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.edge.EdgeEventActionType; import org.thingsboard.server.common.data.edge.EdgeEventActionType;
import org.thingsboard.server.common.data.edge.EdgeEventType; import org.thingsboard.server.common.data.edge.EdgeEventType;
import org.thingsboard.server.common.data.id.EdgeId;
import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.RuleChainId;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.relation.EntityRelation;
@ -55,10 +50,6 @@ import org.thingsboard.server.dao.eventsourcing.DeleteEntityEvent;
import org.thingsboard.server.dao.eventsourcing.RelationActionEvent; import org.thingsboard.server.dao.eventsourcing.RelationActionEvent;
import org.thingsboard.server.dao.eventsourcing.SaveEntityEvent; import org.thingsboard.server.dao.eventsourcing.SaveEntityEvent;
import org.thingsboard.server.dao.tenant.TenantService; import org.thingsboard.server.dao.tenant.TenantService;
import org.thingsboard.server.queue.discovery.TopicService;
import org.thingsboard.server.queue.kafka.TbKafkaAdmin;
import org.thingsboard.server.queue.kafka.TbKafkaSettings;
import org.thingsboard.server.queue.kafka.TbKafkaTopicConfigs;
/** /**
* This event listener does not support async event processing because relay on ThreadLocal * This event listener does not support async event processing because relay on ThreadLocal
@ -79,22 +70,11 @@ import org.thingsboard.server.queue.kafka.TbKafkaTopicConfigs;
@RequiredArgsConstructor @RequiredArgsConstructor
public class EdgeEventSourcingListener { public class EdgeEventSourcingListener {
private final TopicService topicService;
private final TbClusterService tbClusterService; private final TbClusterService tbClusterService;
private final TenantService tenantService; private final TenantService tenantService;
private final EdgeSynchronizationManager edgeSynchronizationManager; private final EdgeSynchronizationManager edgeSynchronizationManager;
@Autowired(required = false)
@Lazy
private TbKafkaSettings kafkaSettings;
@Autowired(required = false)
@Lazy
private TbKafkaTopicConfigs kafkaTopicConfigs;
@Value("#{'${queue.type:null}' == 'kafka'}")
private boolean isKafkaSupported;
@PostConstruct @PostConstruct
public void init() { public void init() {
log.debug("EdgeEventSourcingListener initiated"); log.debug("EdgeEventSourcingListener initiated");
@ -127,11 +107,7 @@ public class EdgeEventSourcingListener {
return; return;
} }
try { try {
if (EntityType.TENANT.equals(entityType)) { if (EntityType.TENANT.equals(entityType) || EntityType.EDGE.equals(entityType)) {
return;
}
if (EntityType.EDGE.equals(entityType)) {
handleEdgeEntityDeletion((EdgeId) event.getEntityId(), tenantId);
return; return;
} }
log.trace("[{}] DeleteEntityEvent called: {}", tenantId, event); log.trace("[{}] DeleteEntityEvent called: {}", tenantId, event);
@ -145,14 +121,6 @@ public class EdgeEventSourcingListener {
} }
} }
private void handleEdgeEntityDeletion(EdgeId edgeId, TenantId tenantId) {
if (isKafkaSupported) {
String topic = topicService.buildEdgeEventNotificationsTopicPartitionInfo(tenantId, edgeId).getTopic();
TbKafkaAdmin kafkaAdmin = new TbKafkaAdmin(kafkaSettings, kafkaTopicConfigs.getEdgeEventConfigs());
kafkaAdmin.deleteTopic(topic);
}
}
private EdgeEventActionType getEdgeEventActionTypeForEntityEvent(Object entity) { private EdgeEventActionType getEdgeEventActionTypeForEntityEvent(Object entity) {
if (entity instanceof AlarmComment) { if (entity instanceof AlarmComment) {
return EdgeEventActionType.DELETED_COMMENT; return EdgeEventActionType.DELETED_COMMENT;

6
application/src/main/java/org/thingsboard/server/service/edge/rpc/AbstractEdgeGrpcSession.java

@ -539,7 +539,8 @@ public abstract class AbstractEdgeGrpcSession<T extends AbstractEdgeGrpcSession<
} }
} }
protected void processHighPriorityEvents() { @Override
public void processHighPriorityEvents() {
try { try {
List<EdgeEvent> highPriorityEvents = new ArrayList<>(); List<EdgeEvent> highPriorityEvents = new ArrayList<>();
EdgeEvent event; EdgeEvent event;
@ -553,7 +554,8 @@ public abstract class AbstractEdgeGrpcSession<T extends AbstractEdgeGrpcSession<
} }
} }
protected ListenableFuture<Boolean> processEdgeEvents() throws Exception { @Override
public ListenableFuture<Boolean> processEdgeEvents() throws Exception {
SettableFuture<Boolean> result = SettableFuture.create(); SettableFuture<Boolean> result = SettableFuture.create();
log.trace("[{}][{}] starting processing edge events", tenantId, sessionId); log.trace("[{}][{}] starting processing edge events", tenantId, sessionId);
if (isConnected() && isSyncCompleted()) { if (isConnected() && isSyncCompleted()) {

62
application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcService.java

@ -57,9 +57,6 @@ import org.thingsboard.server.common.msg.edge.ToEdgeSyncRequest;
import org.thingsboard.server.gen.edge.v1.EdgeRpcServiceGrpc; import org.thingsboard.server.gen.edge.v1.EdgeRpcServiceGrpc;
import org.thingsboard.server.gen.edge.v1.RequestMsg; import org.thingsboard.server.gen.edge.v1.RequestMsg;
import org.thingsboard.server.gen.edge.v1.ResponseMsg; import org.thingsboard.server.gen.edge.v1.ResponseMsg;
import org.thingsboard.server.gen.transport.TransportProtos.ToEdgeEventNotificationMsg;
import org.thingsboard.server.queue.TbQueueConsumer;
import org.thingsboard.server.queue.common.TbProtoQueueMsg;
import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; import org.thingsboard.server.queue.discovery.TbServiceInfoProvider;
import org.thingsboard.server.queue.provider.TbCoreQueueFactory; import org.thingsboard.server.queue.provider.TbCoreQueueFactory;
import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.queue.util.TbCoreComponent;
@ -95,7 +92,6 @@ public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase i
private final ConcurrentMap<EdgeId, ScheduledFuture<?>> sessionEdgeEventChecks = new ConcurrentHashMap<>(); private final ConcurrentMap<EdgeId, ScheduledFuture<?>> sessionEdgeEventChecks = new ConcurrentHashMap<>();
private final ConcurrentMap<UUID, Consumer<FromEdgeSyncResponse>> localSyncEdgeRequests = new ConcurrentHashMap<>(); private final ConcurrentMap<UUID, Consumer<FromEdgeSyncResponse>> localSyncEdgeRequests = new ConcurrentHashMap<>();
private final ConcurrentMap<EdgeId, Boolean> edgeEventsProcessed = new ConcurrentHashMap<>(); private final ConcurrentMap<EdgeId, Boolean> edgeEventsProcessed = new ConcurrentHashMap<>();
private final ConcurrentMap<EdgeId, Boolean> kafkaConsumerInit = new ConcurrentHashMap<>();
@Value("${edges.rpc.port}") @Value("${edges.rpc.port}")
private int rpcPort; private int rpcPort;
@ -220,7 +216,7 @@ public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase i
private AbstractEdgeGrpcSession<?> createEdgeGrpcSession(StreamObserver<ResponseMsg> outputStream) { private AbstractEdgeGrpcSession<?> createEdgeGrpcSession(StreamObserver<ResponseMsg> outputStream) {
return isKafkaSupported return isKafkaSupported
? new KafkaEdgeGrpcSession(ctx, outputStream, this::onEdgeConnect, this::onEdgeDisconnect, ? new KafkaEdgeGrpcSession(ctx, tbCoreQueueFactory, outputStream, this::onEdgeConnect, this::onEdgeDisconnect,
sendDownlinkExecutorService, maxInboundMessageSize, maxHighPriorityQueueSizePerSession) sendDownlinkExecutorService, maxInboundMessageSize, maxHighPriorityQueueSizePerSession)
: new PostgresEdgeGrpcSession(ctx, outputStream, this::onEdgeConnect, this::onEdgeDisconnect, : new PostgresEdgeGrpcSession(ctx, outputStream, this::onEdgeConnect, this::onEdgeDisconnect,
sendDownlinkExecutorService, maxInboundMessageSize, maxHighPriorityQueueSizePerSession); sendDownlinkExecutorService, maxInboundMessageSize, maxHighPriorityQueueSizePerSession);
@ -333,26 +329,7 @@ public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase i
pushRuleEngineMessage(tenantId, edge, lastConnectTs, TbMsgType.CONNECT_EVENT); pushRuleEngineMessage(tenantId, edge, lastConnectTs, TbMsgType.CONNECT_EVENT);
cancelScheduleEdgeEventsCheck(edgeId); cancelScheduleEdgeEventsCheck(edgeId);
edgeEventsProcessed.putIfAbsent(edgeId, Boolean.FALSE); edgeEventsProcessed.putIfAbsent(edgeId, Boolean.FALSE);
if (edgeGrpcSession instanceof KafkaEdgeGrpcSession session) { scheduleEdgeEventsCheck(edgeGrpcSession);
Boolean isChecked = edgeEventsProcessed.get(edgeId);
if (Boolean.FALSE.equals(isChecked)) {
scheduleEdgeEventsCheck(session);
} else {
initializeKafkaConsumer(session, tenantId, edgeId);
}
}
if (edgeGrpcSession instanceof PostgresEdgeGrpcSession) {
scheduleEdgeEventsCheck(edgeGrpcSession);
}
}
private void initializeKafkaConsumer(KafkaEdgeGrpcSession kafkaEdgeGrpcSession, TenantId tenantId, EdgeId edgeId) {
TbQueueConsumer<TbProtoQueueMsg<ToEdgeEventNotificationMsg>> consumer = tbCoreQueueFactory.createEdgeEventMsgConsumer(tenantId, edgeId);
if (!kafkaConsumerInit.getOrDefault(edgeId, Boolean.FALSE)) {
kafkaEdgeGrpcSession.initConsumer(() -> consumer, schedulerPoolSize);
kafkaEdgeGrpcSession.startConsumers();
kafkaConsumerInit.put(edgeId, Boolean.TRUE);
}
} }
private void startSyncProcess(TenantId tenantId, EdgeId edgeId, UUID requestId, String requestServiceId) { private void startSyncProcess(TenantId tenantId, EdgeId edgeId, UUID requestId, String requestServiceId) {
@ -419,22 +396,18 @@ public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase i
final Lock newEventLock = sessionNewEventsLocks.computeIfAbsent(edgeId, id -> new ReentrantLock()); final Lock newEventLock = sessionNewEventsLocks.computeIfAbsent(edgeId, id -> new ReentrantLock());
newEventLock.lock(); newEventLock.lock();
try { try {
if (Boolean.TRUE.equals(sessionNewEvents.get(edgeId)) && Boolean.FALSE.equals(edgeEventsProcessed.get(edgeId))) { if (Boolean.TRUE.equals(sessionNewEvents.get(edgeId))) {
log.trace("[{}][{}] Set session new events flag to false", tenantId, edgeId.getId()); log.trace("[{}][{}] Set session new events flag to false", tenantId, edgeId.getId());
sessionNewEvents.put(edgeId, false); sessionNewEvents.put(edgeId, false);
processEdgeEventMigrationIfNeeded(session, edgeId);
session.processHighPriorityEvents();
Futures.addCallback(session.processEdgeEvents(), new FutureCallback<>() { Futures.addCallback(session.processEdgeEvents(), new FutureCallback<>() {
@Override @Override
public void onSuccess(Boolean newEventsAdded) { public void onSuccess(Boolean newEventsAdded) {
if (Boolean.TRUE.equals(newEventsAdded)) { if (Boolean.TRUE.equals(newEventsAdded)) {
sessionNewEvents.put(edgeId, true); sessionNewEvents.put(edgeId, true);
} }
if (session instanceof KafkaEdgeGrpcSession kafkaEdgeGrpcSession && newEventsAdded != null) { scheduleEdgeEventsCheck(session);
edgeEventsProcessed.put(edgeId, true);
initializeKafkaConsumer(kafkaEdgeGrpcSession, tenantId, edgeId);
cancelScheduleEdgeEventsCheck(edgeId);
} else {
scheduleEdgeEventsCheck(session);
}
} }
@Override @Override
@ -444,12 +417,7 @@ public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase i
} }
}, ctx.getGrpcCallbackExecutorService()); }, ctx.getGrpcCallbackExecutorService());
} else { } else {
if (Boolean.TRUE.equals(edgeEventsProcessed.get(edgeId)) && session instanceof KafkaEdgeGrpcSession kafkaEdgeGrpcSession) { scheduleEdgeEventsCheck(session);
initializeKafkaConsumer(kafkaEdgeGrpcSession, tenantId, edgeId);
cancelScheduleEdgeEventsCheck(edgeId);
} else {
scheduleEdgeEventsCheck(session);
}
} }
} finally { } finally {
newEventLock.unlock(); newEventLock.unlock();
@ -466,6 +434,21 @@ public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase i
} }
} }
private void processEdgeEventMigrationIfNeeded(AbstractEdgeGrpcSession<?> session, EdgeId edgeId) throws Exception {
boolean isMigrationProcessed = edgeEventsProcessed.getOrDefault(edgeId, Boolean.FALSE);
if (!isMigrationProcessed) {
Boolean migrated = session.migrateEdgeEvents(false).get();
if (Boolean.TRUE.equals(migrated)) {
sessionNewEvents.put(edgeId, true);
scheduleEdgeEventsCheck(session);
} else if (Boolean.FALSE.equals(migrated)) {
edgeEventsProcessed.put(edgeId, true);
} else {
scheduleEdgeEventsCheck(session);
}
}
}
private void cancelScheduleEdgeEventsCheck(EdgeId edgeId) { private void cancelScheduleEdgeEventsCheck(EdgeId edgeId) {
log.trace("[{}] cancelling edge event check for edge", edgeId); log.trace("[{}] cancelling edge event check for edge", edgeId);
if (sessionEdgeEventChecks.containsKey(edgeId)) { if (sessionEdgeEventChecks.containsKey(edgeId)) {
@ -492,7 +475,6 @@ public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase i
} }
if (isKafkaSupported) { if (isKafkaSupported) {
((KafkaEdgeGrpcSession) toRemove).stopConsumer(); ((KafkaEdgeGrpcSession) toRemove).stopConsumer();
kafkaConsumerInit.remove(edgeId);
} }
TenantId tenantId = toRemove.getEdge().getTenantId(); TenantId tenantId = toRemove.getEdge().getTenantId();
save(tenantId, edgeId, DefaultDeviceStateService.ACTIVITY_STATE, false); save(tenantId, edgeId, DefaultDeviceStateService.ACTIVITY_STATE, false);

7
application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcSession.java

@ -15,6 +15,7 @@
*/ */
package org.thingsboard.server.service.edge.rpc; package org.thingsboard.server.service.edge.rpc;
import com.google.common.util.concurrent.ListenableFuture;
import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.edge.Edge;
public interface EdgeGrpcSession { public interface EdgeGrpcSession {
@ -25,4 +26,10 @@ public interface EdgeGrpcSession {
boolean isConnected(); boolean isConnected();
ListenableFuture<Boolean> migrateEdgeEvents(boolean isMigrationProcessed) throws Exception;
ListenableFuture<Boolean> processEdgeEvents() throws Exception;
void processHighPriorityEvents();
} }

120
application/src/main/java/org/thingsboard/server/service/edge/rpc/KafkaEdgeGrpcSession.java

@ -15,6 +15,8 @@
*/ */
package org.thingsboard.server.service.edge.rpc; package org.thingsboard.server.service.edge.rpc;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import io.grpc.stub.StreamObserver; import io.grpc.stub.StreamObserver;
import jakarta.annotation.PreDestroy; import jakarta.annotation.PreDestroy;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -29,6 +31,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.ToEdgeEventNotificat
import org.thingsboard.server.queue.TbQueueConsumer; import org.thingsboard.server.queue.TbQueueConsumer;
import org.thingsboard.server.queue.common.TbProtoQueueMsg; import org.thingsboard.server.queue.common.TbProtoQueueMsg;
import org.thingsboard.server.queue.common.consumer.QueueConsumerManager; import org.thingsboard.server.queue.common.consumer.QueueConsumerManager;
import org.thingsboard.server.queue.provider.TbCoreQueueFactory;
import org.thingsboard.server.service.edge.EdgeContextComponent; import org.thingsboard.server.service.edge.EdgeContextComponent;
import java.util.ArrayList; import java.util.ArrayList;
@ -37,86 +40,50 @@ import java.util.UUID;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
import java.util.function.Supplier;
@Slf4j @Slf4j
public class KafkaEdgeGrpcSession extends AbstractEdgeGrpcSession<KafkaEdgeGrpcSession> { public class KafkaEdgeGrpcSession extends AbstractEdgeGrpcSession<KafkaEdgeGrpcSession> {
private ExecutorService consumerExecutor; private final TbQueueConsumer<TbProtoQueueMsg<ToEdgeEventNotificationMsg>> edgeEventsConsumer;
private ScheduledExecutorService highPriorityExecutorService;
private volatile boolean isHighPriorityProcessing;
private volatile boolean isConsumerInit;
private QueueConsumerManager<TbProtoQueueMsg<ToEdgeEventNotificationMsg>> consumer; private QueueConsumerManager<TbProtoQueueMsg<ToEdgeEventNotificationMsg>> consumer;
public KafkaEdgeGrpcSession(EdgeContextComponent ctx, StreamObserver<ResponseMsg> outputStream, private ExecutorService consumerExecutor;
public KafkaEdgeGrpcSession(EdgeContextComponent ctx, TbCoreQueueFactory tbCoreQueueFactory, StreamObserver<ResponseMsg> outputStream,
BiConsumer<EdgeId, KafkaEdgeGrpcSession> sessionOpenListener, BiConsumer<EdgeId, KafkaEdgeGrpcSession> sessionOpenListener,
BiConsumer<Edge, UUID> sessionCloseListener, BiConsumer<Edge, UUID> sessionCloseListener, ScheduledExecutorService sendDownlinkExecutorService,
ScheduledExecutorService sendDownlinkExecutorService,
int maxInboundMessageSize, int maxHighPriorityQueueSizePerSession) { int maxInboundMessageSize, int maxHighPriorityQueueSizePerSession) {
super(ctx, outputStream, sessionOpenListener, sessionCloseListener, sendDownlinkExecutorService, maxInboundMessageSize, maxHighPriorityQueueSizePerSession); super(ctx, outputStream, sessionOpenListener, sessionCloseListener, sendDownlinkExecutorService, maxInboundMessageSize, maxHighPriorityQueueSizePerSession);
} edgeEventsConsumer = tbCoreQueueFactory.createEdgeEventMsgConsumer(tenantId, edge.getId());
protected void initConsumer(Supplier<TbQueueConsumer<TbProtoQueueMsg<ToEdgeEventNotificationMsg>>> edgeEventsConsumer, long schedulerPoolSize) {
this.consumerExecutor = Executors.newSingleThreadExecutor(ThingsBoardThreadFactory.forName("edge-event-consumer"));
this.highPriorityExecutorService = Executors.newScheduledThreadPool((int) schedulerPoolSize, ThingsBoardThreadFactory.forName("edge-event-high-priority-scheduler"));
this.consumer = QueueConsumerManager.<TbProtoQueueMsg<ToEdgeEventNotificationMsg>>builder()
.name("TB Edge events")
.msgPackProcessor(this::processMsgs)
.pollInterval(ctx.getEdgeEventStorageSettings().getNoRecordsSleepInterval())
.consumerCreator(edgeEventsConsumer)
.consumerExecutor(consumerExecutor)
.threadPrefix("edge-events")
.build();
scheduleCheckForHighPriorityEvent();
} }
private void processMsgs(List<TbProtoQueueMsg<ToEdgeEventNotificationMsg>> msgs, TbQueueConsumer<TbProtoQueueMsg<ToEdgeEventNotificationMsg>> consumer) { private void processMsgs(List<TbProtoQueueMsg<ToEdgeEventNotificationMsg>> msgs, TbQueueConsumer<TbProtoQueueMsg<ToEdgeEventNotificationMsg>> consumer) {
log.trace("[{}][{}] starting processing edge events", tenantId, sessionId); log.trace("[{}][{}] starting processing edge events", tenantId, sessionId);
if (isConnected() && isSyncCompleted()) { if (isConnected() && isSyncCompleted() && !isHighPriorityProcessing) {
List<EdgeEvent> edgeEvents = new ArrayList<>();
if (!highPriorityQueue.isEmpty()) { for (TbProtoQueueMsg<ToEdgeEventNotificationMsg> msg : msgs) {
processHighPriorityEvents(); EdgeEvent edgeEvent = ProtoUtils.fromProto(msg.getValue().getEdgeEventMsg());
} else { edgeEvents.add(edgeEvent);
List<EdgeEvent> edgeEvents = new ArrayList<>();
for (TbProtoQueueMsg<ToEdgeEventNotificationMsg> msg : msgs) {
EdgeEvent edgeEvent = ProtoUtils.fromProto(msg.getValue().getEdgeEventMsg());
edgeEvents.add(edgeEvent);
}
List<DownlinkMsg> downlinkMsgsPack = convertToDownlinkMsgsPack(edgeEvents);
try {
boolean isInterrupted = sendDownlinkMsgsPack(downlinkMsgsPack).get();
if (isInterrupted) {
log.debug("[{}][{}][{}] Send downlink messages task was interrupted", tenantId, edge.getId(), sessionId);
} else {
consumer.commit();
}
} catch (Exception e) {
log.error("[{}] Failed to process all downlink messages", sessionId, e);
}
} }
} else { List<DownlinkMsg> downlinkMsgsPack = convertToDownlinkMsgsPack(edgeEvents);
log.trace("[{}][{}] edge is not connected or sync is not completed. Skipping iteration", tenantId, sessionId);
}
}
private void scheduleCheckForHighPriorityEvent() {
highPriorityExecutorService.scheduleAtFixedRate(() -> {
try { try {
if (isConnected() && isSyncCompleted()) { boolean isInterrupted = sendDownlinkMsgsPack(downlinkMsgsPack).get();
if (!highPriorityQueue.isEmpty()) { if (isInterrupted) {
processHighPriorityEvents(); log.debug("[{}][{}][{}] Send downlink messages task was interrupted", tenantId, edge.getId(), sessionId);
} } else {
consumer.commit();
} }
} catch (Exception e) { } catch (Exception e) {
log.error("Error in processing high priority events", e); log.error("[{}] Failed to process all downlink messages", sessionId, e);
} }
}, 0, ctx.getEdgeEventStorageSettings().getNoRecordsSleepInterval() * 3, TimeUnit.MILLISECONDS); } else {
} log.trace("[{}][{}] edge is not connected or sync is not completed. Skipping iteration", tenantId, sessionId);
}
public void startConsumers() {
consumer.subscribe();
consumer.launch();
} }
@PreDestroy @PreDestroy
@ -130,4 +97,37 @@ public class KafkaEdgeGrpcSession extends AbstractEdgeGrpcSession<KafkaEdgeGrpcS
consumerExecutor.shutdown(); consumerExecutor.shutdown();
} }
@Override
public ListenableFuture<Boolean> migrateEdgeEvents(boolean isMigrationProcessed) throws Exception {
if (isMigrationProcessed) {
return Futures.immediateFuture(Boolean.FALSE);
}
return super.processEdgeEvents();
}
@Override
public ListenableFuture<Boolean> processEdgeEvents() {
if (!isConsumerInit) {
this.consumerExecutor = Executors.newSingleThreadExecutor(ThingsBoardThreadFactory.forName("edge-event-consumer"));
this.consumer = QueueConsumerManager.<TbProtoQueueMsg<ToEdgeEventNotificationMsg>>builder()
.name("TB Edge events")
.msgPackProcessor(this::processMsgs)
.pollInterval(ctx.getEdgeEventStorageSettings().getNoRecordsSleepInterval())
.consumerCreator(() -> edgeEventsConsumer)
.consumerExecutor(consumerExecutor)
.threadPrefix("edge-events")
.build();
isConsumerInit = true;
consumer.subscribe();
consumer.launch();
}
return Futures.immediateFuture(Boolean.FALSE);
}
@Override
public void processHighPriorityEvents() {
isHighPriorityProcessing = true;
super.processHighPriorityEvents();
}
} }

7
application/src/main/java/org/thingsboard/server/service/edge/rpc/PostgresEdgeGrpcSession.java

@ -15,6 +15,8 @@
*/ */
package org.thingsboard.server.service.edge.rpc; package org.thingsboard.server.service.edge.rpc;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import io.grpc.stub.StreamObserver; import io.grpc.stub.StreamObserver;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.edge.Edge;
@ -37,4 +39,9 @@ public class PostgresEdgeGrpcSession extends AbstractEdgeGrpcSession<PostgresEdg
initInputStream(); initInputStream();
} }
@Override
public ListenableFuture<Boolean> migrateEdgeEvents(boolean isMigrationProcessed) {
return Futures.immediateFuture(Boolean.FALSE);
}
} }

37
application/src/main/java/org/thingsboard/server/service/entitiy/EntityStateSourcingListener.java

@ -17,7 +17,6 @@ package org.thingsboard.server.service.entitiy;
import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.core.type.TypeReference;
import jakarta.annotation.PostConstruct; import jakarta.annotation.PostConstruct;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.transaction.event.TransactionalEventListener; import org.springframework.transaction.event.TransactionalEventListener;
@ -35,6 +34,7 @@ import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.edge.EdgeEvent; import org.thingsboard.server.common.data.edge.EdgeEvent;
import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.EdgeId;
import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.RuleChainId;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
@ -54,17 +54,34 @@ import org.thingsboard.server.dao.eventsourcing.ActionEntityEvent;
import org.thingsboard.server.dao.eventsourcing.DeleteEntityEvent; import org.thingsboard.server.dao.eventsourcing.DeleteEntityEvent;
import org.thingsboard.server.dao.eventsourcing.SaveEntityEvent; import org.thingsboard.server.dao.eventsourcing.SaveEntityEvent;
import org.thingsboard.server.dao.tenant.TenantService; import org.thingsboard.server.dao.tenant.TenantService;
import org.thingsboard.server.queue.discovery.TopicService;
import org.thingsboard.server.queue.kafka.TbKafkaAdmin;
import org.thingsboard.server.queue.kafka.TbKafkaSettings;
import org.thingsboard.server.queue.kafka.TbKafkaTopicConfigs;
import java.util.Optional;
import java.util.Set; import java.util.Set;
@Component
@RequiredArgsConstructor
@Slf4j @Slf4j
@Component
public class EntityStateSourcingListener { public class EntityStateSourcingListener {
private final TopicService topicService;
private final TbClusterService tbClusterService; private final TbClusterService tbClusterService;
private final TenantService tenantService; private final TenantService tenantService;
private final Optional<TbKafkaSettings> kafkaSettings;
private final Optional<TbKafkaTopicConfigs> kafkaTopicConfigs;
public EntityStateSourcingListener(TopicService topicService, TbClusterService tbClusterService, TenantService tenantService,
Optional<TbKafkaSettings> kafkaSettings, Optional<TbKafkaTopicConfigs> kafkaTopicConfigs) {
this.topicService = topicService;
this.tbClusterService = tbClusterService;
this.tenantService = tenantService;
this.kafkaSettings = kafkaSettings;
this.kafkaTopicConfigs = kafkaTopicConfigs;
}
@PostConstruct @PostConstruct
public void init() { public void init() {
log.debug("EntityStateSourcingListener initiated"); log.debug("EntityStateSourcingListener initiated");
@ -137,7 +154,7 @@ public class EntityStateSourcingListener {
log.debug("[{}][{}][{}] Handling entity deletion event: {}", tenantId, entityType, entityId, event); log.debug("[{}][{}][{}] Handling entity deletion event: {}", tenantId, entityType, entityId, event);
switch (entityType) { switch (entityType) {
case ASSET, ASSET_PROFILE, ENTITY_VIEW, CUSTOMER, EDGE, NOTIFICATION_RULE -> { case ASSET, ASSET_PROFILE, ENTITY_VIEW, CUSTOMER, NOTIFICATION_RULE -> {
tbClusterService.broadcastEntityStateChangeEvent(tenantId, entityId, ComponentLifecycleEvent.DELETED); tbClusterService.broadcastEntityStateChangeEvent(tenantId, entityId, ComponentLifecycleEvent.DELETED);
} }
case NOTIFICATION_REQUEST -> { case NOTIFICATION_REQUEST -> {
@ -177,6 +194,10 @@ public class EntityStateSourcingListener {
TbResourceInfo tbResource = (TbResourceInfo) event.getEntity(); TbResourceInfo tbResource = (TbResourceInfo) event.getEntity();
tbClusterService.onResourceDeleted(tbResource, null); tbClusterService.onResourceDeleted(tbResource, null);
} }
case EDGE -> {
onEdgeDelete(tenantId, (EdgeId) event.getEntityId());
tbClusterService.broadcastEntityStateChangeEvent(tenantId, entityId, ComponentLifecycleEvent.DELETED);
}
default -> {} default -> {}
} }
} }
@ -247,6 +268,14 @@ public class EntityStateSourcingListener {
} }
} }
private void onEdgeDelete(TenantId tenantId, EdgeId edgeId) {
if (kafkaSettings.isPresent() && kafkaTopicConfigs.isPresent()) {
String topic = topicService.buildEdgeEventNotificationsTopicPartitionInfo(tenantId, edgeId).getTopic();
TbKafkaAdmin kafkaAdmin = new TbKafkaAdmin(kafkaSettings.get(), kafkaTopicConfigs.get().getEdgeEventConfigs());
kafkaAdmin.deleteTopic(topic);
}
}
private void pushAssignedFromNotification(Tenant currentTenant, TenantId newTenantId, Device assignedDevice) { private void pushAssignedFromNotification(Tenant currentTenant, TenantId newTenantId, Device assignedDevice) {
String data = JacksonUtil.toString(JacksonUtil.valueToTree(assignedDevice)); String data = JacksonUtil.toString(JacksonUtil.valueToTree(assignedDevice));
if (data != null) { if (data != null) {

Loading…
Cancel
Save