From 52d7da7afd934d6a21002b4794c5730c21399cf2 Mon Sep 17 00:00:00 2001 From: dlandiak Date: Fri, 4 Nov 2022 10:33:08 +0200 Subject: [PATCH 1/5] inactivity timeout fix - get from attr when persist to telemetry and default found --- .../state/DefaultDeviceStateService.java | 27 +++++++++++- .../state/DefaultDeviceStateServiceTest.java | 41 ++++++++++++++++++- 2 files changed, 65 insertions(+), 3 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java b/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java index c9c54161dd..38f4ee50c7 100644 --- a/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java +++ b/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java @@ -24,6 +24,7 @@ import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListeningExecutorService; import com.google.common.util.concurrent.MoreExecutors; import lombok.Getter; +import lombok.Setter; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; @@ -83,6 +84,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Optional; import java.util.Random; import java.util.Set; import java.util.UUID; @@ -152,6 +154,7 @@ public class DefaultDeviceStateService extends AbstractPartitionBasedService attributeOpt = attributesService.find(TenantId.SYS_TENANT_ID, deviceStateData.getDeviceId(), SERVER_SCOPE, INACTIVITY_TIMEOUT).get(); + attributeOpt.flatMap(KvEntry::getLongValue).ifPresent((inactivityTimeout) -> { + if (inactivityTimeout > 0) { + deviceStateData.getState().setInactivityTimeout(inactivityTimeout); + } + }); + } catch (Exception e) { + log.warn("[{}] Failed to fetch inactivity timeout from attribute", deviceStateData.getDeviceId(), e); + } + } } private EntityKeyType getKeyType() { diff --git a/application/src/test/java/org/thingsboard/server/service/state/DefaultDeviceStateServiceTest.java b/application/src/test/java/org/thingsboard/server/service/state/DefaultDeviceStateServiceTest.java index d5d74f2512..bc0e067442 100644 --- a/application/src/test/java/org/thingsboard/server/service/state/DefaultDeviceStateServiceTest.java +++ b/application/src/test/java/org/thingsboard/server/service/state/DefaultDeviceStateServiceTest.java @@ -15,27 +15,45 @@ */ package org.thingsboard.server.service.state; +import com.google.common.util.concurrent.Futures; +import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.junit.MockitoJUnitRunner; +import org.thingsboard.server.cluster.TbClusterService; +import org.thingsboard.server.common.data.DeviceIdInfo; import org.thingsboard.server.common.data.id.DeviceId; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry; +import org.thingsboard.server.common.data.kv.LongDataEntry; +import org.thingsboard.server.common.data.query.EntityData; +import org.thingsboard.server.common.data.query.EntityKeyType; +import org.thingsboard.server.common.data.query.TsValue; import org.thingsboard.server.dao.attributes.AttributesService; import org.thingsboard.server.dao.device.DeviceService; import org.thingsboard.server.dao.tenant.TenantService; import org.thingsboard.server.dao.timeseries.TimeseriesService; import org.thingsboard.server.queue.discovery.PartitionService; -import org.thingsboard.server.cluster.TbClusterService; import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; +import java.util.Map; +import java.util.Optional; +import java.util.UUID; + import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.BDDMockito.willReturn; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; +import static org.mockito.Mockito.when; +import static org.thingsboard.server.common.data.DataConstants.SERVER_SCOPE; +import static org.thingsboard.server.service.state.DefaultDeviceStateService.INACTIVITY_TIMEOUT; @RunWith(MockitoJUnitRunner.class) public class DefaultDeviceStateServiceTest { @@ -83,4 +101,25 @@ public class DefaultDeviceStateServiceTest { Mockito.verify(service, times(1)).fetchDeviceStateDataUsingEntityDataQuery(deviceId); } + @Test + public void givenPersistToTelemetryAndDefaultInactivityTimeoutFetched_whenTransformingToDeviceStateData_thenTryGetInactivityFromAttribute() { + var defaultInactivityTimeoutInSec = 60L; + service.setDefaultInactivityTimeoutInSec(defaultInactivityTimeoutInSec); + service.setPersistToTelemetry(true); + + var deviceUuid = UUID.randomUUID(); + var deviceId = new DeviceId(deviceUuid); + + when(attributesService.find(any(), any(), anyString(), anyString())) + .thenReturn(Futures.immediateFuture(Optional.of(new BaseAttributeKvEntry(0, new LongDataEntry(INACTIVITY_TIMEOUT, 5000L))))); + + var latest = + Map.of(EntityKeyType.TIME_SERIES, Map.of(INACTIVITY_TIMEOUT, new TsValue(0, Long.toString(defaultInactivityTimeoutInSec * 1000)))); + DeviceStateData deviceStateData = service.toDeviceStateData(new EntityData(deviceId, latest, Map.of()), new DeviceIdInfo(TenantId.SYS_TENANT_ID.getId(), UUID.randomUUID(), deviceUuid)); + + Mockito.verify(attributesService, times(1)).find(TenantId.SYS_TENANT_ID, deviceId, SERVER_SCOPE, INACTIVITY_TIMEOUT); + + Assert.assertEquals(5000L, deviceStateData.getState().getInactivityTimeout()); + } + } \ No newline at end of file From 3cb94532fabd40fa67a1394234daad74c48a90f5 Mon Sep 17 00:00:00 2001 From: dlandiak Date: Wed, 9 Nov 2022 14:03:37 +0200 Subject: [PATCH 2/5] get inactivity using entity data query instead of separate attribute fetch request --- .../state/DefaultDeviceStateService.java | 20 ++++------- .../state/DefaultDeviceStateServiceTest.java | 36 +++++++++++-------- 2 files changed, 27 insertions(+), 29 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java b/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java index 38f4ee50c7..4aaba9c6ea 100644 --- a/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java +++ b/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java @@ -84,7 +84,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; -import java.util.Optional; import java.util.Random; import java.util.Set; import java.util.UUID; @@ -123,7 +122,8 @@ public class DefaultDeviceStateService extends AbstractPartitionBasedService PERSISTENT_ATTRIBUTE_KEYS = Arrays.asList( new EntityKey(EntityKeyType.SERVER_ATTRIBUTE, LAST_ACTIVITY_TIME), @@ -662,24 +662,16 @@ public class DefaultDeviceStateService extends AbstractPartitionBasedService attributeOpt = attributesService.find(TenantId.SYS_TENANT_ID, deviceStateData.getDeviceId(), SERVER_SCOPE, INACTIVITY_TIMEOUT).get(); - attributeOpt.flatMap(KvEntry::getLongValue).ifPresent((inactivityTimeout) -> { - if (inactivityTimeout > 0) { - deviceStateData.getState().setInactivityTimeout(inactivityTimeout); - } - }); - } catch (Exception e) { - log.warn("[{}] Failed to fetch inactivity timeout from attribute", deviceStateData.getDeviceId(), e); - } + long inactivityTimeout = getEntryValue(ed, EntityKeyType.SERVER_ATTRIBUTE, INACTIVITY_TIMEOUT, TimeUnit.SECONDS.toMillis(defaultInactivityTimeoutInSec)); + deviceStateData.getState().setInactivityTimeout(inactivityTimeout); } } diff --git a/application/src/test/java/org/thingsboard/server/service/state/DefaultDeviceStateServiceTest.java b/application/src/test/java/org/thingsboard/server/service/state/DefaultDeviceStateServiceTest.java index bc0e067442..b33b7162c4 100644 --- a/application/src/test/java/org/thingsboard/server/service/state/DefaultDeviceStateServiceTest.java +++ b/application/src/test/java/org/thingsboard/server/service/state/DefaultDeviceStateServiceTest.java @@ -15,7 +15,6 @@ */ package org.thingsboard.server.service.state; -import com.google.common.util.concurrent.Futures; import org.junit.Assert; import org.junit.Before; import org.junit.Test; @@ -27,8 +26,6 @@ import org.thingsboard.server.cluster.TbClusterService; import org.thingsboard.server.common.data.DeviceIdInfo; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.TenantId; -import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry; -import org.thingsboard.server.common.data.kv.LongDataEntry; import org.thingsboard.server.common.data.query.EntityData; import org.thingsboard.server.common.data.query.EntityKeyType; import org.thingsboard.server.common.data.query.TsValue; @@ -40,19 +37,14 @@ import org.thingsboard.server.queue.discovery.PartitionService; import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; import java.util.Map; -import java.util.Optional; import java.util.UUID; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.BDDMockito.willReturn; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; -import static org.mockito.Mockito.when; -import static org.thingsboard.server.common.data.DataConstants.SERVER_SCOPE; import static org.thingsboard.server.service.state.DefaultDeviceStateService.INACTIVITY_TIMEOUT; @RunWith(MockitoJUnitRunner.class) @@ -104,21 +96,35 @@ public class DefaultDeviceStateServiceTest { @Test public void givenPersistToTelemetryAndDefaultInactivityTimeoutFetched_whenTransformingToDeviceStateData_thenTryGetInactivityFromAttribute() { var defaultInactivityTimeoutInSec = 60L; + var latest = + Map.of( + EntityKeyType.TIME_SERIES, Map.of(INACTIVITY_TIMEOUT, new TsValue(0, Long.toString(defaultInactivityTimeoutInSec * 1000))), + EntityKeyType.SERVER_ATTRIBUTE, Map.of(INACTIVITY_TIMEOUT, new TsValue(0, Long.toString(5000L))) + ); + + process(latest, defaultInactivityTimeoutInSec); + } + + @Test + public void givenPersistToTelemetryAndNoInactivityTimeoutFetchedFromTimeSeries_whenTransformingToDeviceStateData_thenTryGetInactivityFromAttribute() { + var defaultInactivityTimeoutInSec = 60L; + var latest = + Map.of( + EntityKeyType.SERVER_ATTRIBUTE, Map.of(INACTIVITY_TIMEOUT, new TsValue(0, Long.toString(5000L))) + ); + + process(latest, defaultInactivityTimeoutInSec); + } + + private void process(Map> latest, long defaultInactivityTimeoutInSec) { service.setDefaultInactivityTimeoutInSec(defaultInactivityTimeoutInSec); service.setPersistToTelemetry(true); var deviceUuid = UUID.randomUUID(); var deviceId = new DeviceId(deviceUuid); - when(attributesService.find(any(), any(), anyString(), anyString())) - .thenReturn(Futures.immediateFuture(Optional.of(new BaseAttributeKvEntry(0, new LongDataEntry(INACTIVITY_TIMEOUT, 5000L))))); - - var latest = - Map.of(EntityKeyType.TIME_SERIES, Map.of(INACTIVITY_TIMEOUT, new TsValue(0, Long.toString(defaultInactivityTimeoutInSec * 1000)))); DeviceStateData deviceStateData = service.toDeviceStateData(new EntityData(deviceId, latest, Map.of()), new DeviceIdInfo(TenantId.SYS_TENANT_ID.getId(), UUID.randomUUID(), deviceUuid)); - Mockito.verify(attributesService, times(1)).find(TenantId.SYS_TENANT_ID, deviceId, SERVER_SCOPE, INACTIVITY_TIMEOUT); - Assert.assertEquals(5000L, deviceStateData.getState().getInactivityTimeout()); } From 4ca140f306a026b6315f0de9f5f69cc6a26a4143 Mon Sep 17 00:00:00 2001 From: dlandiak Date: Wed, 9 Nov 2022 15:01:15 +0200 Subject: [PATCH 3/5] device state svc refactoring --- .../state/DefaultDeviceStateService.java | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java b/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java index 4aaba9c6ea..ed9949a379 100644 --- a/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java +++ b/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java @@ -642,6 +642,11 @@ public class DefaultDeviceStateService extends AbstractPartitionBasedService Date: Wed, 9 Nov 2022 15:47:12 +0200 Subject: [PATCH 4/5] added defaultInactivityTimeoutMs param to device state svc --- .../service/state/DefaultDeviceStateService.java | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java b/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java index ed9949a379..a223d97c96 100644 --- a/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java +++ b/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java @@ -157,6 +157,9 @@ public class DefaultDeviceStateService extends AbstractPartitionBasedService transformInactivityTimeout(ListenableFuture future) { return Futures.transformAsync(future, deviceStateData -> { - if (!persistToTelemetry || deviceStateData.getState().getInactivityTimeout() != TimeUnit.SECONDS.toMillis(defaultInactivityTimeoutInSec)) { + if (!persistToTelemetry || deviceStateData.getState().getInactivityTimeout() != defaultInactivityTimeoutMs) { return future; //fail fast } var attributesFuture = attributesService.find(TenantId.SYS_TENANT_ID, deviceStateData.getDeviceId(), SERVER_SCOPE, INACTIVITY_TIMEOUT); @@ -567,7 +570,7 @@ public class DefaultDeviceStateService extends AbstractPartitionBasedService Date: Wed, 9 Nov 2022 15:57:18 +0200 Subject: [PATCH 5/5] fix tests in device state svc --- .../server/service/state/DefaultDeviceStateService.java | 2 ++ .../server/service/state/DefaultDeviceStateServiceTest.java | 1 + 2 files changed, 3 insertions(+) diff --git a/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java b/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java index a223d97c96..d52c712074 100644 --- a/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java +++ b/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java @@ -158,6 +158,8 @@ public class DefaultDeviceStateService extends AbstractPartitionBasedService> latest, long defaultInactivityTimeoutInSec) { service.setDefaultInactivityTimeoutInSec(defaultInactivityTimeoutInSec); + service.setDefaultInactivityTimeoutMs(defaultInactivityTimeoutInSec * 1000); service.setPersistToTelemetry(true); var deviceUuid = UUID.randomUUID();