Commit 8869dc0cb0a9a8eb3fb84b3e3045c79b973afd9d

Authored by YevhenBondarenko
1 parent 6436c8a2

added new RPC statuses

@@ -400,6 +400,14 @@ public class ActorSystemContext { @@ -400,6 +400,14 @@ public class ActorSystemContext {
400 @Getter 400 @Getter
401 private String debugPerTenantLimitsConfiguration; 401 private String debugPerTenantLimitsConfiguration;
402 402
  403 + @Value("${actors.rpc.sequence.enabled:true}")
  404 + @Getter
  405 + private boolean rpcSequenceEnabled;
  406 +
  407 + @Value("${actors.rpc.persistent.retries:5}")
  408 + @Getter
  409 + private int maxPersistentRpcRetries;
  410 +
403 @Getter 411 @Getter
404 @Setter 412 @Setter
405 private TbActorSystem actorSystem; 413 private TbActorSystem actorSystem;
@@ -121,6 +121,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { @@ -121,6 +121,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor {
121 private final Map<UUID, SessionInfo> attributeSubscriptions; 121 private final Map<UUID, SessionInfo> attributeSubscriptions;
122 private final Map<UUID, SessionInfo> rpcSubscriptions; 122 private final Map<UUID, SessionInfo> rpcSubscriptions;
123 private final Map<Integer, ToDeviceRpcRequestMetadata> toDeviceRpcPendingMap; 123 private final Map<Integer, ToDeviceRpcRequestMetadata> toDeviceRpcPendingMap;
  124 + private final boolean rpcSequenceEnabled;
124 125
125 private int rpcSeq = 0; 126 private int rpcSeq = 0;
126 private String deviceName; 127 private String deviceName;
@@ -132,6 +133,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { @@ -132,6 +133,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor {
132 super(systemContext); 133 super(systemContext);
133 this.tenantId = tenantId; 134 this.tenantId = tenantId;
134 this.deviceId = deviceId; 135 this.deviceId = deviceId;
  136 + this.rpcSequenceEnabled = systemContext.isRpcSequenceEnabled();
135 this.attributeSubscriptions = new HashMap<>(); 137 this.attributeSubscriptions = new HashMap<>();
136 this.rpcSubscriptions = new HashMap<>(); 138 this.rpcSubscriptions = new HashMap<>();
137 this.toDeviceRpcPendingMap = new LinkedHashMap<>(); 139 this.toDeviceRpcPendingMap = new LinkedHashMap<>();
@@ -185,19 +187,19 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { @@ -185,19 +187,19 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor {
185 if (timeout <= 0) { 187 if (timeout <= 0) {
186 log.debug("[{}][{}] Ignoring message due to exp time reached, {}", deviceId, request.getId(), request.getExpirationTime()); 188 log.debug("[{}][{}] Ignoring message due to exp time reached, {}", deviceId, request.getId(), request.getExpirationTime());
187 if (persisted) { 189 if (persisted) {
188 - createRpc(request, RpcStatus.TIMEOUT); 190 + createRpc(request, RpcStatus.EXPIRED);
189 } 191 }
190 return; 192 return;
191 } else if (persisted) { 193 } else if (persisted) {
192 createRpc(request, RpcStatus.QUEUED); 194 createRpc(request, RpcStatus.QUEUED);
193 } 195 }
194 196
195 - boolean sent; 197 + boolean sent = false;
196 if (systemContext.isEdgesEnabled() && edgeId != null) { 198 if (systemContext.isEdgesEnabled() && edgeId != null) {
197 log.debug("[{}][{}] device is related to edge [{}]. Saving RPC request to edge queue", tenantId, deviceId, edgeId.getId()); 199 log.debug("[{}][{}] device is related to edge [{}]. Saving RPC request to edge queue", tenantId, deviceId, edgeId.getId());
198 saveRpcRequestToEdgeQueue(request, rpcRequest.getRequestId()); 200 saveRpcRequestToEdgeQueue(request, rpcRequest.getRequestId());
199 sent = true; 201 sent = true;
200 - } else { 202 + } else if (!rpcSequenceEnabled || toDeviceRpcPendingMap.isEmpty()) {
201 sent = rpcSubscriptions.size() > 0; 203 sent = rpcSubscriptions.size() > 0;
202 Set<UUID> syncSessionSet = new HashSet<>(); 204 Set<UUID> syncSessionSet = new HashSet<>();
203 rpcSubscriptions.forEach((key, value) -> { 205 rpcSubscriptions.forEach((key, value) -> {
@@ -292,7 +294,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { @@ -292,7 +294,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor {
292 if (requestMd != null) { 294 if (requestMd != null) {
293 log.debug("[{}] RPC request [{}] timeout detected!", deviceId, msg.getId()); 295 log.debug("[{}] RPC request [{}] timeout detected!", deviceId, msg.getId());
294 if (requestMd.getMsg().getMsg().isPersisted()) { 296 if (requestMd.getMsg().getMsg().isPersisted()) {
295 - systemContext.getTbRpcService().save(tenantId, new RpcId(requestMd.getMsg().getMsg().getId()), RpcStatus.TIMEOUT, null); 297 + systemContext.getTbRpcService().save(tenantId, new RpcId(requestMd.getMsg().getMsg().getId()), RpcStatus.EXPIRED, null);
296 } 298 }
297 systemContext.getTbCoreDeviceRpcService().processRpcResponseFromDeviceActor(new FromDeviceRpcResponse(requestMd.getMsg().getMsg().getId(), 299 systemContext.getTbCoreDeviceRpcService().processRpcResponseFromDeviceActor(new FromDeviceRpcResponse(requestMd.getMsg().getMsg().getId(),
298 null, requestMd.isSent() ? RpcError.TIMEOUT : RpcError.NO_ACTIVE_CONNECTION)); 300 null, requestMd.isSent() ? RpcError.TIMEOUT : RpcError.NO_ACTIVE_CONNECTION));
@@ -300,7 +302,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { @@ -300,7 +302,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor {
300 } 302 }
301 } 303 }
302 304
303 - private void sendPendingRequest(TbActorCtx context, UUID sessionId, String nodeId) { 305 + private void sendPendingRequests(TbActorCtx context, UUID sessionId, String nodeId) {
304 SessionType sessionType = getSessionType(sessionId); 306 SessionType sessionType = getSessionType(sessionId);
305 if (!toDeviceRpcPendingMap.isEmpty()) { 307 if (!toDeviceRpcPendingMap.isEmpty()) {
306 log.debug("[{}] Pushing {} pending RPC messages to new async session [{}]", deviceId, toDeviceRpcPendingMap.size(), sessionId); 308 log.debug("[{}] Pushing {} pending RPC messages to new async session [{}]", deviceId, toDeviceRpcPendingMap.size(), sessionId);
@@ -312,11 +314,34 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { @@ -312,11 +314,34 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor {
312 log.debug("[{}] No pending RPC messages for new async session [{}]", deviceId, sessionId); 314 log.debug("[{}] No pending RPC messages for new async session [{}]", deviceId, sessionId);
313 } 315 }
314 Set<Integer> sentOneWayIds = new HashSet<>(); 316 Set<Integer> sentOneWayIds = new HashSet<>();
315 - toDeviceRpcPendingMap.entrySet().stream().findFirst().ifPresent(processPendingRpc(context, sessionId, nodeId, sentOneWayIds)); 317 +
  318 + if (sessionType == SessionType.ASYNC) {
  319 + if (rpcSequenceEnabled) {
  320 + List<Map.Entry<Integer, ToDeviceRpcRequestMetadata>> entries = new ArrayList<>();
  321 + for (Map.Entry<Integer, ToDeviceRpcRequestMetadata> entry : toDeviceRpcPendingMap.entrySet()) {
  322 + if (entry.getValue().isDelivered()) {
  323 + continue;
  324 + }
  325 + entries.add(entry);
  326 + if (entry.getValue().getMsg().getMsg().isPersisted() || entry.getValue().getMsg().getMsg().isOneway()) {
  327 + break;
  328 + }
  329 + }
  330 + entries.forEach(processPendingRpc(context, sessionId, nodeId, sentOneWayIds));
  331 + } else {
  332 + toDeviceRpcPendingMap.entrySet().forEach(processPendingRpc(context, sessionId, nodeId, sentOneWayIds));
  333 + }
  334 + } else {
  335 + toDeviceRpcPendingMap.entrySet().stream().findFirst().ifPresent(processPendingRpc(context, sessionId, nodeId, sentOneWayIds));
  336 + }
  337 +
  338 + sentOneWayIds.stream().filter(id -> !toDeviceRpcPendingMap.get(id).getMsg().getMsg().isPersisted()).forEach(toDeviceRpcPendingMap::remove);
316 } 339 }
317 340
318 private void sendNextPendingRequest(TbActorCtx context) { 341 private void sendNextPendingRequest(TbActorCtx context) {
319 - rpcSubscriptions.forEach((id, s) -> sendPendingRequest(context, id, s.getNodeId())); 342 + if (rpcSequenceEnabled) {
  343 + rpcSubscriptions.forEach((id, s) -> sendPendingRequests(context, id, s.getNodeId()));
  344 + }
320 } 345 }
321 346
322 private Consumer<Map.Entry<Integer, ToDeviceRpcRequestMetadata>> processPendingRpc(TbActorCtx context, UUID sessionId, String nodeId, Set<Integer> sentOneWayIds) { 347 private Consumer<Map.Entry<Integer, ToDeviceRpcRequestMetadata>> processPendingRpc(TbActorCtx context, UUID sessionId, String nodeId, Set<Integer> sentOneWayIds) {
@@ -338,11 +363,6 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { @@ -338,11 +363,6 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor {
338 .setPersisted(request.isPersisted()) 363 .setPersisted(request.isPersisted())
339 .build(); 364 .build();
340 sendToTransport(rpcRequest, sessionId, nodeId); 365 sendToTransport(rpcRequest, sessionId, nodeId);
341 -  
342 - if (SessionType.ASYNC.equals(getSessionType(sessionId)) && request.isOneway() && !request.isPersisted()) {  
343 - toDeviceRpcPendingMap.remove(entry.getKey());  
344 - sendPendingRequest(context, sessionId, nodeId);  
345 - }  
346 }; 366 };
347 } 367 }
348 368
@@ -361,7 +381,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { @@ -361,7 +381,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor {
361 processSubscriptionCommands(context, sessionInfo, msg.getSubscribeToRPC()); 381 processSubscriptionCommands(context, sessionInfo, msg.getSubscribeToRPC());
362 } 382 }
363 if (msg.hasSendPendingRPC()) { 383 if (msg.hasSendPendingRPC()) {
364 - sendPendingRequest(context, getSessionId(sessionInfo), sessionInfo.getNodeId()); 384 + sendPendingRequests(context, getSessionId(sessionInfo), sessionInfo.getNodeId());
365 } 385 }
366 if (msg.hasGetAttributes()) { 386 if (msg.hasGetAttributes()) {
367 handleGetAttributesRequest(context, sessionInfo, msg.getGetAttributes()); 387 handleGetAttributesRequest(context, sessionInfo, msg.getGetAttributes());
@@ -559,16 +579,28 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { @@ -559,16 +579,28 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor {
559 private void processPersistedRpcResponses(TbActorCtx context, SessionInfoProto sessionInfo, ToDevicePersistedRpcResponseMsg responseMsg) { 579 private void processPersistedRpcResponses(TbActorCtx context, SessionInfoProto sessionInfo, ToDevicePersistedRpcResponseMsg responseMsg) {
560 UUID rpcId = new UUID(responseMsg.getRequestIdMSB(), responseMsg.getRequestIdLSB()); 580 UUID rpcId = new UUID(responseMsg.getRequestIdMSB(), responseMsg.getRequestIdLSB());
561 RpcStatus status = RpcStatus.valueOf(responseMsg.getStatus()); 581 RpcStatus status = RpcStatus.valueOf(responseMsg.getStatus());
562 -  
563 - ToDeviceRpcRequestMetadata md;  
564 - if (RpcStatus.DELIVERED.equals(status)) {  
565 - md = toDeviceRpcPendingMap.get(responseMsg.getRequestId());  
566 - } else {  
567 - md = toDeviceRpcPendingMap.remove(responseMsg.getRequestId());  
568 - } 582 + ToDeviceRpcRequestMetadata md = toDeviceRpcPendingMap.get(responseMsg.getRequestId());
569 583
570 if (md != null) { 584 if (md != null) {
  585 + if (status.equals(RpcStatus.DELIVERED)) {
  586 + if (md.getMsg().getMsg().isOneway()) {
  587 + toDeviceRpcPendingMap.remove(responseMsg.getRequestId());
  588 + } else {
  589 + md.setDelivered(true);
  590 + }
  591 + } else if (status.equals(RpcStatus.TIMEOUT)) {
  592 + if (systemContext.getMaxPersistentRpcRetries() <= md.getRetries()) {
  593 + toDeviceRpcPendingMap.remove(responseMsg.getRequestId());
  594 + status = RpcStatus.FAILED;
  595 + } else {
  596 + md.setRetries(md.getRetries() + 1);
  597 + }
  598 + }
  599 +
571 systemContext.getTbRpcService().save(tenantId, new RpcId(rpcId), status, null); 600 systemContext.getTbRpcService().save(tenantId, new RpcId(rpcId), status, null);
  601 + if (status != RpcStatus.SENT) {
  602 + sendNextPendingRequest(context);
  603 + }
572 } else { 604 } else {
573 log.info("[{}][{}] Rpc has already removed from pending map.", deviceId, rpcId); 605 log.info("[{}][{}] Rpc has already removed from pending map.", deviceId, rpcId);
574 } 606 }
@@ -608,7 +640,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { @@ -608,7 +640,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor {
608 sessionMD.setSubscribedToRPC(true); 640 sessionMD.setSubscribedToRPC(true);
609 log.debug("[{}] Registering rpc subscription for session [{}]", deviceId, sessionId); 641 log.debug("[{}] Registering rpc subscription for session [{}]", deviceId, sessionId);
610 rpcSubscriptions.put(sessionId, sessionMD.getSessionInfo()); 642 rpcSubscriptions.put(sessionId, sessionMD.getSessionInfo());
611 - sendPendingRequest(context, sessionId, sessionInfo.getNodeId()); 643 + sendPendingRequests(context, sessionId, sessionInfo.getNodeId());
612 dumpSessions(); 644 dumpSessions();
613 } 645 }
614 } 646 }
@@ -884,7 +916,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { @@ -884,7 +916,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor {
884 ToDeviceRpcRequest msg = JacksonUtil.convertValue(rpc.getRequest(), ToDeviceRpcRequest.class); 916 ToDeviceRpcRequest msg = JacksonUtil.convertValue(rpc.getRequest(), ToDeviceRpcRequest.class);
885 long timeout = rpc.getExpirationTime() - System.currentTimeMillis(); 917 long timeout = rpc.getExpirationTime() - System.currentTimeMillis();
886 if (timeout <= 0) { 918 if (timeout <= 0) {
887 - rpc.setStatus(RpcStatus.TIMEOUT); 919 + rpc.setStatus(RpcStatus.EXPIRED);
888 systemContext.getTbRpcService().save(tenantId, rpc); 920 systemContext.getTbRpcService().save(tenantId, rpc);
889 } else { 921 } else {
890 registerPendingRpcRequest(ctx, new ToDeviceRpcRequestActorMsg(systemContext.getServiceId(), msg), false, creteToDeviceRpcRequestMsg(msg), timeout); 922 registerPendingRpcRequest(ctx, new ToDeviceRpcRequestActorMsg(systemContext.getServiceId(), msg), false, creteToDeviceRpcRequestMsg(msg), timeout);
@@ -25,4 +25,6 @@ import org.thingsboard.server.service.rpc.ToDeviceRpcRequestActorMsg; @@ -25,4 +25,6 @@ import org.thingsboard.server.service.rpc.ToDeviceRpcRequestActorMsg;
25 public class ToDeviceRpcRequestMetadata { 25 public class ToDeviceRpcRequestMetadata {
26 private final ToDeviceRpcRequestActorMsg msg; 26 private final ToDeviceRpcRequestActorMsg msg;
27 private final boolean sent; 27 private final boolean sent;
  28 + private int retries;
  29 + private boolean delivered;
28 } 30 }
@@ -326,6 +326,11 @@ actors: @@ -326,6 +326,11 @@ actors:
326 queue_size: "${ACTORS_RULE_TRANSACTION_QUEUE_SIZE:15000}" 326 queue_size: "${ACTORS_RULE_TRANSACTION_QUEUE_SIZE:15000}"
327 # Time in milliseconds for transaction to complete 327 # Time in milliseconds for transaction to complete
328 duration: "${ACTORS_RULE_TRANSACTION_DURATION:60000}" 328 duration: "${ACTORS_RULE_TRANSACTION_DURATION:60000}"
  329 + rpc:
  330 + persistent:
  331 + retries: "${ACTORS_RPC_PERSISTENT_RETRIES:5}"
  332 + sequence:
  333 + enabled: "${ACTORS_RPC_SEQUENCE_ENABLED:true}"
329 statistics: 334 statistics:
330 # Enable/disable actor statistics 335 # Enable/disable actor statistics
331 enabled: "${ACTORS_STATISTICS_ENABLED:true}" 336 enabled: "${ACTORS_STATISTICS_ENABLED:true}"
@@ -16,5 +16,5 @@ @@ -16,5 +16,5 @@
16 package org.thingsboard.server.common.data.rpc; 16 package org.thingsboard.server.common.data.rpc;
17 17
18 public enum RpcStatus { 18 public enum RpcStatus {
19 - QUEUED, DELIVERED, SUCCESSFUL, TIMEOUT, FAILED 19 + QUEUED, SENT, DELIVERED, SUCCESSFUL, TIMEOUT, EXPIRED, FAILED
20 } 20 }
@@ -42,6 +42,7 @@ import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadCo @@ -42,6 +42,7 @@ import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadCo
42 import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration; 42 import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration;
43 import org.thingsboard.server.common.data.id.DeviceId; 43 import org.thingsboard.server.common.data.id.DeviceId;
44 import org.thingsboard.server.common.data.id.DeviceProfileId; 44 import org.thingsboard.server.common.data.id.DeviceProfileId;
  45 +import org.thingsboard.server.common.data.rpc.RpcStatus;
45 import org.thingsboard.server.common.msg.session.FeatureType; 46 import org.thingsboard.server.common.msg.session.FeatureType;
46 import org.thingsboard.server.common.msg.session.SessionMsgType; 47 import org.thingsboard.server.common.msg.session.SessionMsgType;
47 import org.thingsboard.server.common.transport.SessionMsgListener; 48 import org.thingsboard.server.common.transport.SessionMsgListener;
@@ -532,7 +533,7 @@ public class DefaultCoapClientContext implements CoapClientContext { @@ -532,7 +533,7 @@ public class DefaultCoapClientContext implements CoapClientContext {
532 response.addMessageObserver(new TbCoapMessageObserver(requestId, id -> { 533 response.addMessageObserver(new TbCoapMessageObserver(requestId, id -> {
533 TransportProtos.ToDeviceRpcRequestMsg rpcRequestMsg = transportContext.getRpcAwaitingAck().remove(id); 534 TransportProtos.ToDeviceRpcRequestMsg rpcRequestMsg = transportContext.getRpcAwaitingAck().remove(id);
534 if (rpcRequestMsg != null) { 535 if (rpcRequestMsg != null) {
535 - transportService.process(state.getSession(), rpcRequestMsg, TransportServiceCallback.EMPTY); 536 + transportService.process(state.getSession(), rpcRequestMsg, RpcStatus.DELIVERED, TransportServiceCallback.EMPTY);
536 } 537 }
537 }, null)); 538 }, null));
538 } 539 }
@@ -553,8 +554,12 @@ public class DefaultCoapClientContext implements CoapClientContext { @@ -553,8 +554,12 @@ public class DefaultCoapClientContext implements CoapClientContext {
553 transportService.process(state.getSession(), 554 transportService.process(state.getSession(),
554 TransportProtos.ToDeviceRpcResponseMsg.newBuilder() 555 TransportProtos.ToDeviceRpcResponseMsg.newBuilder()
555 .setRequestId(msg.getRequestId()).setError(error).build(), TransportServiceCallback.EMPTY); 556 .setRequestId(msg.getRequestId()).setError(error).build(), TransportServiceCallback.EMPTY);
556 - } else if (msg.getPersisted() && !conRequest && sent) {  
557 - transportService.process(state.getSession(), msg, TransportServiceCallback.EMPTY); 557 + } else if (msg.getPersisted() && sent) {
  558 + if (conRequest) {
  559 + transportService.process(state.getSession(), msg, RpcStatus.SENT, TransportServiceCallback.EMPTY);
  560 + } else {
  561 + transportService.process(state.getSession(), msg, RpcStatus.DELIVERED, TransportServiceCallback.EMPTY);
  562 + }
558 } 563 }
559 } 564 }
560 } 565 }
@@ -409,7 +409,7 @@ public class DeviceApiController implements TbTransportService { @@ -409,7 +409,7 @@ public class DeviceApiController implements TbTransportService {
409 public void onToDeviceRpcRequest(UUID sessionId, ToDeviceRpcRequestMsg msg) { 409 public void onToDeviceRpcRequest(UUID sessionId, ToDeviceRpcRequestMsg msg) {
410 log.trace("[{}] Received RPC command to device", sessionId); 410 log.trace("[{}] Received RPC command to device", sessionId);
411 responseWriter.setResult(new ResponseEntity<>(JsonConverter.toJson(msg, true).toString(), HttpStatus.OK)); 411 responseWriter.setResult(new ResponseEntity<>(JsonConverter.toJson(msg, true).toString(), HttpStatus.OK));
412 - transportService.process(sessionInfo, msg, TransportServiceCallback.EMPTY); 412 + transportService.process(sessionInfo, msg, RpcStatus.DELIVERED, TransportServiceCallback.EMPTY);
413 } 413 }
414 414
415 @Override 415 @Override
@@ -21,7 +21,9 @@ import org.eclipse.leshan.core.ResponseCode; @@ -21,7 +21,9 @@ import org.eclipse.leshan.core.ResponseCode;
21 import org.springframework.stereotype.Service; 21 import org.springframework.stereotype.Service;
22 import org.thingsboard.common.util.JacksonUtil; 22 import org.thingsboard.common.util.JacksonUtil;
23 import org.thingsboard.server.common.data.StringUtils; 23 import org.thingsboard.server.common.data.StringUtils;
  24 +import org.thingsboard.server.common.data.rpc.RpcStatus;
24 import org.thingsboard.server.common.transport.TransportService; 25 import org.thingsboard.server.common.transport.TransportService;
  26 +import org.thingsboard.server.common.transport.TransportServiceCallback;
25 import org.thingsboard.server.gen.transport.TransportProtos; 27 import org.thingsboard.server.gen.transport.TransportProtos;
26 import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; 28 import org.thingsboard.server.queue.util.TbLwM2mTransportComponent;
27 import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; 29 import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig;
@@ -158,6 +160,7 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler { @@ -158,6 +160,7 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler {
158 throw new IllegalArgumentException("Unsupported operation: " + operationType.name()); 160 throw new IllegalArgumentException("Unsupported operation: " + operationType.name());
159 } 161 }
160 } 162 }
  163 + transportService.process(client.getSession(), rpcRequest, RpcStatus.SENT, TransportServiceCallback.EMPTY);
161 } catch (IllegalArgumentException e) { 164 } catch (IllegalArgumentException e) {
162 this.sendErrorRpcResponse(sessionInfo, rpcRequest.getRequestId(), ResponseCode.BAD_REQUEST, e.getMessage()); 165 this.sendErrorRpcResponse(sessionInfo, rpcRequest.getRequestId(), ResponseCode.BAD_REQUEST, e.getMessage());
163 } 166 }
@@ -19,6 +19,7 @@ import org.eclipse.leshan.core.ResponseCode; @@ -19,6 +19,7 @@ import org.eclipse.leshan.core.ResponseCode;
19 import org.eclipse.leshan.core.request.exception.ClientSleepingException; 19 import org.eclipse.leshan.core.request.exception.ClientSleepingException;
20 import org.thingsboard.common.util.JacksonUtil; 20 import org.thingsboard.common.util.JacksonUtil;
21 import org.thingsboard.server.common.data.StringUtils; 21 import org.thingsboard.server.common.data.StringUtils;
  22 +import org.thingsboard.server.common.data.rpc.RpcStatus;
22 import org.thingsboard.server.common.transport.TransportService; 23 import org.thingsboard.server.common.transport.TransportService;
23 import org.thingsboard.server.common.transport.TransportServiceCallback; 24 import org.thingsboard.server.common.transport.TransportServiceCallback;
24 import org.thingsboard.server.gen.transport.TransportProtos; 25 import org.thingsboard.server.gen.transport.TransportProtos;
@@ -44,7 +45,7 @@ public abstract class RpcDownlinkRequestCallbackProxy<R, T> implements DownlinkR @@ -44,7 +45,7 @@ public abstract class RpcDownlinkRequestCallbackProxy<R, T> implements DownlinkR
44 45
45 @Override 46 @Override
46 public void onSuccess(R request, T response) { 47 public void onSuccess(R request, T response) {
47 - transportService.process(client.getSession(), this.request, TransportServiceCallback.EMPTY); 48 + transportService.process(client.getSession(), this.request, RpcStatus.DELIVERED, TransportServiceCallback.EMPTY);
48 sendRpcReplyOnSuccess(response); 49 sendRpcReplyOnSuccess(response);
49 if (callback != null) { 50 if (callback != null) {
50 callback.onSuccess(request, response); 51 callback.onSuccess(request, response);
@@ -61,7 +62,9 @@ public abstract class RpcDownlinkRequestCallbackProxy<R, T> implements DownlinkR @@ -61,7 +62,9 @@ public abstract class RpcDownlinkRequestCallbackProxy<R, T> implements DownlinkR
61 62
62 @Override 63 @Override
63 public void onError(String params, Exception e) { 64 public void onError(String params, Exception e) {
64 - if (!(e instanceof TimeoutException || e instanceof ClientSleepingException)) { 65 + if (e instanceof TimeoutException) {
  66 + transportService.process(client.getSession(), this.request, RpcStatus.TIMEOUT, TransportServiceCallback.EMPTY);
  67 + } else if (!(e instanceof ClientSleepingException)) {
65 sendRpcReplyOnError(e); 68 sendRpcReplyOnError(e);
66 } 69 }
67 if (callback != null) { 70 if (callback != null) {
@@ -50,6 +50,7 @@ import org.thingsboard.server.common.data.TransportPayloadType; @@ -50,6 +50,7 @@ import org.thingsboard.server.common.data.TransportPayloadType;
50 import org.thingsboard.server.common.data.device.profile.MqttTopics; 50 import org.thingsboard.server.common.data.device.profile.MqttTopics;
51 import org.thingsboard.server.common.data.id.OtaPackageId; 51 import org.thingsboard.server.common.data.id.OtaPackageId;
52 import org.thingsboard.server.common.data.ota.OtaPackageType; 52 import org.thingsboard.server.common.data.ota.OtaPackageType;
  53 +import org.thingsboard.server.common.data.rpc.RpcStatus;
53 import org.thingsboard.server.common.msg.EncryptionUtil; 54 import org.thingsboard.server.common.msg.EncryptionUtil;
54 import org.thingsboard.server.common.msg.tools.TbRateLimitsException; 55 import org.thingsboard.server.common.msg.tools.TbRateLimitsException;
55 import org.thingsboard.server.common.transport.SessionMsgListener; 56 import org.thingsboard.server.common.transport.SessionMsgListener;
@@ -272,7 +273,7 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement @@ -272,7 +273,7 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement
272 int msgId = ((MqttPubAckMessage) msg).variableHeader().messageId(); 273 int msgId = ((MqttPubAckMessage) msg).variableHeader().messageId();
273 TransportProtos.ToDeviceRpcRequestMsg rpcRequest = rpcAwaitingAck.remove(msgId); 274 TransportProtos.ToDeviceRpcRequestMsg rpcRequest = rpcAwaitingAck.remove(msgId);
274 if (rpcRequest != null) { 275 if (rpcRequest != null) {
275 - transportService.process(deviceSessionCtx.getSessionInfo(), rpcRequest, TransportServiceCallback.EMPTY); 276 + transportService.process(deviceSessionCtx.getSessionInfo(), rpcRequest, RpcStatus.DELIVERED, TransportServiceCallback.EMPTY);
276 } 277 }
277 break; 278 break;
278 default: 279 default:
@@ -856,10 +857,14 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement @@ -856,10 +857,14 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement
856 }, Math.max(0, rpcRequest.getExpirationTime() - System.currentTimeMillis()), TimeUnit.MILLISECONDS); 857 }, Math.max(0, rpcRequest.getExpirationTime() - System.currentTimeMillis()), TimeUnit.MILLISECONDS);
857 } 858 }
858 var cf = publish(payload, deviceSessionCtx); 859 var cf = publish(payload, deviceSessionCtx);
859 - if (rpcRequest.getPersisted() && !isAckExpected(payload)) { 860 + if (rpcRequest.getPersisted()) {
860 cf.addListener(result -> { 861 cf.addListener(result -> {
861 if (result.cause() == null) { 862 if (result.cause() == null) {
862 - transportService.process(deviceSessionCtx.getSessionInfo(), rpcRequest, TransportServiceCallback.EMPTY); 863 + if (isAckExpected(payload)) {
  864 + transportService.process(deviceSessionCtx.getSessionInfo(), rpcRequest, RpcStatus.SENT, TransportServiceCallback.EMPTY);
  865 + } else {
  866 + transportService.process(deviceSessionCtx.getSessionInfo(), rpcRequest, RpcStatus.DELIVERED, TransportServiceCallback.EMPTY);
  867 + }
863 } 868 }
864 }); 869 });
865 } 870 }
@@ -16,8 +16,10 @@ @@ -16,8 +16,10 @@
16 package org.thingsboard.server.transport.mqtt.session; 16 package org.thingsboard.server.transport.mqtt.session;
17 17
18 import io.netty.channel.ChannelFuture; 18 import io.netty.channel.ChannelFuture;
  19 +import io.netty.handler.codec.mqtt.MqttMessage;
19 import lombok.extern.slf4j.Slf4j; 20 import lombok.extern.slf4j.Slf4j;
20 import org.thingsboard.server.common.data.DeviceProfile; 21 import org.thingsboard.server.common.data.DeviceProfile;
  22 +import org.thingsboard.server.common.data.rpc.RpcStatus;
21 import org.thingsboard.server.common.transport.SessionMsgListener; 23 import org.thingsboard.server.common.transport.SessionMsgListener;
22 import org.thingsboard.server.common.transport.TransportService; 24 import org.thingsboard.server.common.transport.TransportService;
23 import org.thingsboard.server.common.transport.TransportServiceCallback; 25 import org.thingsboard.server.common.transport.TransportServiceCallback;
@@ -102,9 +104,13 @@ public class GatewayDeviceSessionCtx extends MqttDeviceAwareSessionContext imple @@ -102,9 +104,13 @@ public class GatewayDeviceSessionCtx extends MqttDeviceAwareSessionContext imple
102 payload -> { 104 payload -> {
103 ChannelFuture channelFuture = parent.writeAndFlush(payload); 105 ChannelFuture channelFuture = parent.writeAndFlush(payload);
104 if (request.getPersisted()) { 106 if (request.getPersisted()) {
105 - channelFuture.addListener(future -> {  
106 - if (future.cause() == null) {  
107 - transportService.process(getSessionInfo(), request, TransportServiceCallback.EMPTY); 107 + channelFuture.addListener(result -> {
  108 + if (result.cause() == null) {
  109 + if (isAckExpected(payload)) {
  110 + transportService.process(getSessionInfo(), request, RpcStatus.SENT, TransportServiceCallback.EMPTY);
  111 + } else {
  112 + transportService.process(getSessionInfo(), request, RpcStatus.DELIVERED, TransportServiceCallback.EMPTY);
  113 + }
108 } 114 }
109 }); 115 });
110 } 116 }
@@ -129,4 +135,8 @@ public class GatewayDeviceSessionCtx extends MqttDeviceAwareSessionContext imple @@ -129,4 +135,8 @@ public class GatewayDeviceSessionCtx extends MqttDeviceAwareSessionContext imple
129 // This feature is not supported in the TB IoT Gateway yet. 135 // This feature is not supported in the TB IoT Gateway yet.
130 } 136 }
131 137
  138 + private boolean isAckExpected(MqttMessage message) {
  139 + return message.fixedHeader().qosLevel().value() > 0;
  140 + }
  141 +
132 } 142 }
@@ -26,6 +26,7 @@ import org.thingsboard.server.common.data.DeviceProfile; @@ -26,6 +26,7 @@ import org.thingsboard.server.common.data.DeviceProfile;
26 import org.thingsboard.server.common.data.device.data.SnmpDeviceTransportConfiguration; 26 import org.thingsboard.server.common.data.device.data.SnmpDeviceTransportConfiguration;
27 import org.thingsboard.server.common.data.device.profile.SnmpDeviceProfileTransportConfiguration; 27 import org.thingsboard.server.common.data.device.profile.SnmpDeviceProfileTransportConfiguration;
28 import org.thingsboard.server.common.data.id.DeviceId; 28 import org.thingsboard.server.common.data.id.DeviceId;
  29 +import org.thingsboard.server.common.data.rpc.RpcStatus;
29 import org.thingsboard.server.common.transport.SessionMsgListener; 30 import org.thingsboard.server.common.transport.SessionMsgListener;
30 import org.thingsboard.server.common.transport.TransportServiceCallback; 31 import org.thingsboard.server.common.transport.TransportServiceCallback;
31 import org.thingsboard.server.common.transport.session.DeviceAwareSessionContext; 32 import org.thingsboard.server.common.transport.session.DeviceAwareSessionContext;
@@ -142,7 +143,7 @@ public class DeviceSessionContext extends DeviceAwareSessionContext implements S @@ -142,7 +143,7 @@ public class DeviceSessionContext extends DeviceAwareSessionContext implements S
142 public void onToDeviceRpcRequest(UUID sessionId, ToDeviceRpcRequestMsg toDeviceRequest) { 143 public void onToDeviceRpcRequest(UUID sessionId, ToDeviceRpcRequestMsg toDeviceRequest) {
143 log.trace("[{}] Received RPC command to device", sessionId); 144 log.trace("[{}] Received RPC command to device", sessionId);
144 snmpTransportContext.getSnmpTransportService().onToDeviceRpcRequest(this, toDeviceRequest); 145 snmpTransportContext.getSnmpTransportService().onToDeviceRpcRequest(this, toDeviceRequest);
145 - snmpTransportContext.getTransportService().process(getSessionInfo(), toDeviceRequest, TransportServiceCallback.EMPTY); 146 + snmpTransportContext.getTransportService().process(getSessionInfo(), toDeviceRequest, RpcStatus.DELIVERED, TransportServiceCallback.EMPTY);
146 } 147 }
147 148
148 @Override 149 @Override
@@ -17,6 +17,7 @@ package org.thingsboard.server.common.transport; @@ -17,6 +17,7 @@ package org.thingsboard.server.common.transport;
17 17
18 import org.thingsboard.server.common.data.DeviceProfile; 18 import org.thingsboard.server.common.data.DeviceProfile;
19 import org.thingsboard.server.common.data.DeviceTransportType; 19 import org.thingsboard.server.common.data.DeviceTransportType;
  20 +import org.thingsboard.server.common.data.rpc.RpcStatus;
20 import org.thingsboard.server.common.transport.auth.GetOrCreateDeviceFromGatewayResponse; 21 import org.thingsboard.server.common.transport.auth.GetOrCreateDeviceFromGatewayResponse;
21 import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse; 22 import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse;
22 import org.thingsboard.server.common.transport.service.SessionMetaData; 23 import org.thingsboard.server.common.transport.service.SessionMetaData;
@@ -112,7 +113,7 @@ public interface TransportService { @@ -112,7 +113,7 @@ public interface TransportService {
112 113
113 void process(SessionInfoProto sessionInfo, ToServerRpcRequestMsg msg, TransportServiceCallback<Void> callback); 114 void process(SessionInfoProto sessionInfo, ToServerRpcRequestMsg msg, TransportServiceCallback<Void> callback);
114 115
115 - void process(SessionInfoProto sessionInfo, ToDeviceRpcRequestMsg msg, TransportServiceCallback<Void> callback); 116 + void process(SessionInfoProto sessionInfo, ToDeviceRpcRequestMsg msg, RpcStatus rpcStatus, TransportServiceCallback<Void> callback);
116 117
117 void process(SessionInfoProto sessionInfo, SubscriptionInfoProto msg, TransportServiceCallback<Void> callback); 118 void process(SessionInfoProto sessionInfo, SubscriptionInfoProto msg, TransportServiceCallback<Void> callback);
118 119
@@ -580,15 +580,13 @@ public class DefaultTransportService implements TransportService { @@ -580,15 +580,13 @@ public class DefaultTransportService implements TransportService {
580 } 580 }
581 581
582 @Override 582 @Override
583 - public void process(TransportProtos.SessionInfoProto sessionInfo, TransportProtos.ToDeviceRpcRequestMsg msg, TransportServiceCallback<Void> callback) { 583 + public void process(TransportProtos.SessionInfoProto sessionInfo, TransportProtos.ToDeviceRpcRequestMsg msg, RpcStatus rpcStatus, TransportServiceCallback<Void> callback) {
584 if (msg.getPersisted()) { 584 if (msg.getPersisted()) {
585 - RpcStatus status = msg.getOneway() ? RpcStatus.SUCCESSFUL : RpcStatus.DELIVERED;  
586 -  
587 TransportProtos.ToDevicePersistedRpcResponseMsg responseMsg = TransportProtos.ToDevicePersistedRpcResponseMsg.newBuilder() 585 TransportProtos.ToDevicePersistedRpcResponseMsg responseMsg = TransportProtos.ToDevicePersistedRpcResponseMsg.newBuilder()
588 .setRequestId(msg.getRequestId()) 586 .setRequestId(msg.getRequestId())
589 .setRequestIdLSB(msg.getRequestIdLSB()) 587 .setRequestIdLSB(msg.getRequestIdLSB())
590 .setRequestIdMSB(msg.getRequestIdMSB()) 588 .setRequestIdMSB(msg.getRequestIdMSB())
591 - .setStatus(status.name()) 589 + .setStatus(rpcStatus.name())
592 .build(); 590 .build();
593 591
594 if (checkLimits(sessionInfo, responseMsg, callback)) { 592 if (checkLimits(sessionInfo, responseMsg, callback)) {