Browse Source

Introduce urgent API usage keys for quicker usage state update

pull/15020/head
Viacheslav Klimov 4 months ago
parent
commit
c1044a989e
  1. 2
      application/src/main/resources/thingsboard.yml
  2. 41
      application/src/test/java/org/thingsboard/server/service/apiusage/ApiUsageTest.java
  3. 13
      common/data/src/main/java/org/thingsboard/server/common/data/ApiUsageRecordKey.java
  4. 20
      common/queue/src/main/java/org/thingsboard/server/queue/usagestats/DefaultTbApiUsageReportClient.java
  5. 2
      msa/vc-executor/src/main/resources/tb-vc-executor.yml
  6. 2
      transport/coap/src/main/resources/tb-coap-transport.yml
  7. 2
      transport/http/src/main/resources/tb-http-transport.yml
  8. 2
      transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml
  9. 2
      transport/mqtt/src/main/resources/tb-mqtt-transport.yml
  10. 2
      transport/snmp/src/main/resources/tb-snmp-transport.yml

2
application/src/main/resources/thingsboard.yml

@ -197,6 +197,8 @@ usage:
enabled_per_customer: "${USAGE_STATS_REPORT_PER_CUSTOMER_ENABLED:false}"
# Statistics reporting interval, set to send summarized data every 10 seconds by default
interval: "${USAGE_STATS_REPORT_INTERVAL:60}"
# Reporting interval for urgent keys (e.g. SMS, Email) that require quicker usage state updates
urgent_interval: "${USAGE_STATS_REPORT_URGENT_INTERVAL:10}"
# Amount of statistic messages in pack
pack_size: "${USAGE_STATS_REPORT_PACK_SIZE:1024}"
check:

41
application/src/test/java/org/thingsboard/server/service/apiusage/ApiUsageTest.java

@ -19,6 +19,8 @@ import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.TestPropertySource;
import org.thingsboard.server.common.data.ApiUsageRecordKey;
import org.thingsboard.server.common.data.ApiUsageState;
import org.thingsboard.server.common.data.ApiUsageStateValue;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.SaveDeviceWithCredentialsRequest;
@ -30,6 +32,7 @@ import org.thingsboard.server.common.data.security.DeviceCredentials;
import org.thingsboard.server.common.data.security.DeviceCredentialsType;
import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration;
import org.thingsboard.server.common.data.tenant.profile.TenantProfileData;
import org.thingsboard.server.common.stats.TbApiUsageReportClient;
import org.thingsboard.server.controller.AbstractControllerTest;
import org.thingsboard.server.controller.TbUrlConstants;
import org.thingsboard.server.dao.service.DaoSqlTest;
@ -46,6 +49,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
@TestPropertySource(properties = {
"usage.stats.report.enabled=true",
"usage.stats.report.interval=2",
"usage.stats.report.urgent_interval=1",
"usage.stats.gauge_report_interval=1",
})
public class ApiUsageTest extends AbstractControllerTest {
@ -54,9 +58,12 @@ public class ApiUsageTest extends AbstractControllerTest {
private User tenantAdmin;
private static final int MAX_DP_ENABLE_VALUE = 12;
private static final int MAX_SMS_ENABLE_VALUE = 10;
private static final double WARN_THRESHOLD_VALUE = 0.5;
@Autowired
private ApiUsageStateService apiUsageStateService;
@Autowired
private TbApiUsageReportClient apiUsageReportClient;
@Before
public void beforeTest() throws Exception {
@ -82,7 +89,7 @@ public class ApiUsageTest extends AbstractControllerTest {
}
@Test
public void testTelemetryApiCall() throws Exception {
public void testDbStorageApiUsage() throws Exception {
Device device = createDevice();
assertNotNull(device);
String telemetryPayload = "{\"temperature\":25, \"humidity\":60}";
@ -94,7 +101,8 @@ public class ApiUsageTest extends AbstractControllerTest {
doPostAsync(url, telemetryPayload, String.class, status().isOk());
}
await().atMost(TIMEOUT, TimeUnit.SECONDS).untilAsserted(() -> assertEquals(ApiUsageStateValue.WARNING, apiUsageStateService.findTenantApiUsageState(tenantId).getDbStorageState()));
await().atMost(TIMEOUT, TimeUnit.SECONDS).untilAsserted(() ->
assertEquals(ApiUsageStateValue.WARNING, getUsageState().getDbStorageState()));
long VALUE_DISABLE = (long) (MAX_DP_ENABLE_VALUE - (MAX_DP_ENABLE_VALUE * WARN_THRESHOLD_VALUE)) / 2;
@ -104,10 +112,35 @@ public class ApiUsageTest extends AbstractControllerTest {
await().atMost(TIMEOUT, TimeUnit.SECONDS)
.untilAsserted(() -> {
assertEquals(ApiUsageStateValue.DISABLED, apiUsageStateService.findTenantApiUsageState(tenantId).getDbStorageState());
assertEquals(ApiUsageStateValue.DISABLED, getUsageState().getDbStorageState());
});
}
@Test
public void testSmsApiUsageState() {
long smsWarnThreshold = (long) (MAX_SMS_ENABLE_VALUE * WARN_THRESHOLD_VALUE);
for (int i = 0; i < smsWarnThreshold; i++) {
apiUsageReportClient.report(tenantId, null, ApiUsageRecordKey.SMS_EXEC_COUNT);
}
await().atMost(TIMEOUT, TimeUnit.SECONDS).untilAsserted(() ->
assertEquals(ApiUsageStateValue.WARNING, getUsageState().getSmsExecState()));
long smsDisableCount = MAX_SMS_ENABLE_VALUE - smsWarnThreshold;
for (int i = 0; i < smsDisableCount; i++) {
apiUsageReportClient.report(tenantId, null, ApiUsageRecordKey.SMS_EXEC_COUNT);
}
await().atMost(TIMEOUT, TimeUnit.SECONDS).untilAsserted(() ->
assertEquals(ApiUsageStateValue.DISABLED, getUsageState().getSmsExecState()));
}
private ApiUsageState getUsageState() {
return apiUsageStateService.findTenantApiUsageState(tenantId);
}
private TenantProfile createTenantProfile() {
TenantProfile tenantProfile = new TenantProfile();
tenantProfile.setName("Tenant Profile");
@ -116,6 +149,8 @@ public class ApiUsageTest extends AbstractControllerTest {
TenantProfileData tenantProfileData = new TenantProfileData();
DefaultTenantProfileConfiguration config = DefaultTenantProfileConfiguration.builder()
.maxDPStorageDays(MAX_DP_ENABLE_VALUE)
.maxSms(MAX_SMS_ENABLE_VALUE)
.smsEnabled(true)
.warnThreshold(WARN_THRESHOLD_VALUE)
.build();

13
common/data/src/main/java/org/thingsboard/server/common/data/ApiUsageRecordKey.java

@ -25,8 +25,8 @@ public enum ApiUsageRecordKey {
RE_EXEC_COUNT(ApiFeature.RE, "ruleEngineExecutionCount", "ruleEngineExecutionLimit", "Rule Engine execution"),
JS_EXEC_COUNT(ApiFeature.JS, "jsExecutionCount", "jsExecutionLimit", "JavaScript execution"),
TBEL_EXEC_COUNT(ApiFeature.TBEL, "tbelExecutionCount", "tbelExecutionLimit", "Tbel execution"),
EMAIL_EXEC_COUNT(ApiFeature.EMAIL, "emailCount", "emailLimit", "email message"),
SMS_EXEC_COUNT(ApiFeature.SMS, "smsCount", "smsLimit", "SMS message"),
EMAIL_EXEC_COUNT(ApiFeature.EMAIL, "emailCount", "emailLimit", "email message", true, true),
SMS_EXEC_COUNT(ApiFeature.SMS, "smsCount", "smsLimit", "SMS message", true, true),
CREATED_ALARMS_COUNT(ApiFeature.ALARM, "createdAlarmsCount", "createdAlarmsLimit", "alarm"),
ACTIVE_DEVICES("activeDevicesCount"),
INACTIVE_DEVICES("inactiveDevicesCount");
@ -50,21 +50,24 @@ public enum ApiUsageRecordKey {
private final String unitLabel;
@Getter
private final boolean counter;
@Getter
private final boolean urgent; // urgent keys are reported at a shorter interval for quicker usage state updates
ApiUsageRecordKey(ApiFeature apiFeature, String apiCountKey, String apiLimitKey, String unitLabel) {
this(apiFeature, apiCountKey, apiLimitKey, unitLabel, true);
this(apiFeature, apiCountKey, apiLimitKey, unitLabel, true, false);
}
ApiUsageRecordKey(String apiCountKey) {
this(null, apiCountKey, null, null, false);
this(null, apiCountKey, null, null, false, false);
}
ApiUsageRecordKey(ApiFeature apiFeature, String apiCountKey, String apiLimitKey, String unitLabel, boolean counter) {
ApiUsageRecordKey(ApiFeature apiFeature, String apiCountKey, String apiLimitKey, String unitLabel, boolean counter, boolean urgent) {
this.apiFeature = apiFeature;
this.apiCountKey = apiCountKey;
this.apiLimitKey = apiLimitKey;
this.unitLabel = unitLabel;
this.counter = counter;
this.urgent = urgent;
}
public static ApiUsageRecordKey[] getKeys(ApiFeature feature) {

20
common/queue/src/main/java/org/thingsboard/server/queue/usagestats/DefaultTbApiUsageReportClient.java

@ -63,8 +63,10 @@ public class DefaultTbApiUsageReportClient implements TbApiUsageReportClient {
private boolean enabled;
@Value("${usage.stats.report.enabled_per_customer:false}")
private boolean enabledPerCustomer;
@Value("${usage.stats.report.interval:10}")
@Value("${usage.stats.report.interval:60}")
private int interval;
@Value("${usage.stats.report.urgent_interval:10}")
private int urgentInterval;
@Value("${usage.stats.report.pack_size:1024}")
private int packSize;
@ -83,20 +85,30 @@ public class DefaultTbApiUsageReportClient implements TbApiUsageReportClient {
for (ApiUsageRecordKey key : ApiUsageRecordKey.values()) {
stats.put(key, new ConcurrentHashMap<>());
}
Random random = new Random();
scheduler.scheduleWithFixedDelay(() -> {
try {
reportStats();
reportStats(false);
} catch (Exception e) {
log.warn("Failed to report statistics: ", e);
}
}, new Random().nextInt(interval), interval, TimeUnit.SECONDS);
}, random.nextInt(interval), interval, TimeUnit.SECONDS);
scheduler.scheduleWithFixedDelay(() -> {
try {
reportStats(true);
} catch (Exception e) {
log.warn("Failed to report urgent statistics: ", e);
}
}, random.nextInt(urgentInterval), urgentInterval, TimeUnit.SECONDS);
}
}
private void reportStats() {
private void reportStats(boolean urgent) {
ConcurrentMap<ParentEntity, UsageStatsServiceMsg.Builder> report = new ConcurrentHashMap<>();
for (ApiUsageRecordKey key : ApiUsageRecordKey.values()) {
if (key.isUrgent() != urgent) continue;
ConcurrentMap<ReportLevel, AtomicLong> statsForKey = stats.get(key);
statsForKey.forEach((reportLevel, statsValue) -> {
long value = statsValue.get();

2
msa/vc-executor/src/main/resources/tb-vc-executor.yml

@ -215,6 +215,8 @@ usage:
enabled_per_customer: "${USAGE_STATS_REPORT_PER_CUSTOMER_ENABLED:false}"
# Interval of reporting the statistics. By default, the summarized statistics are sent every 10 seconds
interval: "${USAGE_STATS_REPORT_INTERVAL:60}"
# Reporting interval for urgent keys (e.g. SMS, Email) that require quicker usage state updates
urgent_interval: "${USAGE_STATS_REPORT_URGENT_INTERVAL:10}"
# Amount of statistic messages in pack
pack_size: "${USAGE_STATS_REPORT_PACK_SIZE:1024}"

2
transport/coap/src/main/resources/tb-coap-transport.yml

@ -421,6 +421,8 @@ usage:
enabled_per_customer: "${USAGE_STATS_REPORT_PER_CUSTOMER_ENABLED:false}"
# Interval of reporting the statistics. By default, the summarized statistics are sent every 10 seconds
interval: "${USAGE_STATS_REPORT_INTERVAL:60}"
# Reporting interval for urgent keys (e.g. SMS, Email) that require quicker usage state updates
urgent_interval: "${USAGE_STATS_REPORT_URGENT_INTERVAL:10}"
# Amount of statistic messages in pack
pack_size: "${USAGE_STATS_REPORT_PACK_SIZE:1024}"

2
transport/http/src/main/resources/tb-http-transport.yml

@ -370,6 +370,8 @@ usage:
enabled_per_customer: "${USAGE_STATS_REPORT_PER_CUSTOMER_ENABLED:false}"
# Interval of reporting the statistics. By default, the summarized statistics are sent every 10 seconds
interval: "${USAGE_STATS_REPORT_INTERVAL:60}"
# Reporting interval for urgent keys (e.g. SMS, Email) that require quicker usage state updates
urgent_interval: "${USAGE_STATS_REPORT_URGENT_INTERVAL:10}"
# Amount of statistic messages in pack
pack_size: "${USAGE_STATS_REPORT_PACK_SIZE:1024}"

2
transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml

@ -471,6 +471,8 @@ usage:
enabled_per_customer: "${USAGE_STATS_REPORT_PER_CUSTOMER_ENABLED:false}"
# Interval of reporting the statistics. By default, the summarized statistics are sent every 10 seconds
interval: "${USAGE_STATS_REPORT_INTERVAL:60}"
# Reporting interval for urgent keys (e.g. SMS, Email) that require quicker usage state updates
urgent_interval: "${USAGE_STATS_REPORT_URGENT_INTERVAL:10}"
# Amount of statistic messages in pack
pack_size: "${USAGE_STATS_REPORT_PACK_SIZE:1024}"

2
transport/mqtt/src/main/resources/tb-mqtt-transport.yml

@ -404,6 +404,8 @@ usage:
enabled_per_customer: "${USAGE_STATS_REPORT_PER_CUSTOMER_ENABLED:false}"
# Interval of reporting the statistics. By default, the summarized statistics are sent every 10 seconds
interval: "${USAGE_STATS_REPORT_INTERVAL:60}"
# Reporting interval for urgent keys (e.g. SMS, Email) that require quicker usage state updates
urgent_interval: "${USAGE_STATS_REPORT_URGENT_INTERVAL:10}"
# Amount of statistic messages in pack
pack_size: "${USAGE_STATS_REPORT_PACK_SIZE:1024}"

2
transport/snmp/src/main/resources/tb-snmp-transport.yml

@ -359,6 +359,8 @@ usage:
enabled_per_customer: "${USAGE_STATS_REPORT_PER_CUSTOMER_ENABLED:false}"
# Interval of reporting the statistics. By default, the summarized statistics are sent every 10 seconds
interval: "${USAGE_STATS_REPORT_INTERVAL:60}"
# Reporting interval for urgent keys (e.g. SMS, Email) that require quicker usage state updates
urgent_interval: "${USAGE_STATS_REPORT_URGENT_INTERVAL:10}"
# Amount of statistic messages in pack
pack_size: "${USAGE_STATS_REPORT_PACK_SIZE:1024}"

Loading…
Cancel
Save