Browse Source

added alarm types cache

pull/8825/head
YevhenBondarenko 3 years ago
parent
commit
df2ef64e67
  1. 4
      application/src/main/java/org/thingsboard/server/controller/AlarmController.java
  2. 6
      application/src/main/java/org/thingsboard/server/service/telemetry/DefaultAlarmSubscriptionService.java
  3. 3
      application/src/main/resources/thingsboard.yml
  4. 2
      common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmService.java
  5. 1
      common/data/src/main/java/org/thingsboard/server/common/data/CacheConstants.java
  6. 2
      dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmDao.java
  7. 26
      dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmTypesCacheEvictEvent.java
  8. 36
      dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmTypesCaffeineCache.java
  9. 38
      dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmTypesRedisCache.java
  10. 35
      dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java
  11. 2
      dao/src/main/java/org/thingsboard/server/dao/sql/alarm/AlarmRepository.java
  12. 4
      dao/src/main/java/org/thingsboard/server/dao/sql/alarm/JpaAlarmDao.java
  13. 3
      dao/src/test/resources/application-test.properties
  14. 3
      rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/RuleEngineAlarmService.java

4
application/src/main/java/org/thingsboard/server/controller/AlarmController.java

@ -15,7 +15,6 @@
*/
package org.thingsboard.server.controller;
import com.google.common.util.concurrent.ListenableFuture;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.RequiredArgsConstructor;
@ -506,8 +505,7 @@ public class AlarmController extends BaseController {
@RequestMapping(value = "/alarm/types", method = RequestMethod.GET)
@ResponseBody
public List<EntitySubtype> getAlarmTypes() throws ThingsboardException, ExecutionException, InterruptedException {
ListenableFuture<List<EntitySubtype>> alarmTypes = alarmService.findAlarmTypesByTenantId(getTenantId());
return checkNotNull(alarmTypes.get());
return checkNotNull(alarmService.findAlarmTypesByTenantId(getTenantId()));
}
}

6
application/src/main/java/org/thingsboard/server/service/telemetry/DefaultAlarmSubscriptionService.java

@ -45,15 +45,15 @@ import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.UserId;
import org.thingsboard.server.common.data.notification.rule.trigger.AlarmTrigger;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.query.AlarmData;
import org.thingsboard.server.common.data.query.AlarmDataQuery;
import org.thingsboard.server.common.data.notification.rule.trigger.AlarmTrigger;
import org.thingsboard.server.common.msg.notification.NotificationRuleProcessor;
import org.thingsboard.server.common.msg.queue.TbCallback;
import org.thingsboard.server.common.stats.TbApiUsageReportClient;
import org.thingsboard.server.dao.alarm.AlarmOperationResult;
import org.thingsboard.server.dao.alarm.AlarmService;
import org.thingsboard.server.common.msg.notification.NotificationRuleProcessor;
import org.thingsboard.server.service.apiusage.TbApiUsageStateService;
import org.thingsboard.server.service.entitiy.alarm.TbAlarmCommentService;
import org.thingsboard.server.service.subscription.TbSubscriptionUtils;
@ -238,7 +238,7 @@ public class DefaultAlarmSubscriptionService extends AbstractSubscriptionService
}
@Override
public ListenableFuture<List<EntitySubtype>> findAlarmTypesByTenantId(TenantId tenantId) {
public List<EntitySubtype> findAlarmTypesByTenantId(TenantId tenantId) {
return alarmService.findAlarmTypesByTenantId(tenantId);
}

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

@ -497,6 +497,9 @@ cache:
entityCount:
timeToLiveInMinutes: "${CACHE_SPECS_ENTITY_COUNT_TTL:1440}"
maxSize: "${CACHE_SPECS_ENTITY_COUNT_MAX_SIZE:100000}"
alarmTypes:
timeToLiveInMinutes: "${CACHE_SPECS_ALARM_TYPES_TTL:60}"
maxSize: "${CACHE_SPECS_ALARM_TYPES_MAX_SIZE:10000}"
# deliberately placed outside 'specs' group above
notificationRules:

2
common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmService.java

@ -124,5 +124,5 @@ public interface AlarmService extends EntityDaoService {
long countAlarmsByQuery(TenantId tenantId, CustomerId customerId, AlarmCountQuery query);
ListenableFuture<List<EntitySubtype>> findAlarmTypesByTenantId(TenantId tenantId);
List<EntitySubtype> findAlarmTypesByTenantId(TenantId tenantId);
}

1
common/data/src/main/java/org/thingsboard/server/common/data/CacheConstants.java

@ -44,4 +44,5 @@ public class CacheConstants {
public static final String USER_SETTINGS_CACHE = "userSettings";
public static final String DASHBOARD_TITLES_CACHE = "dashboardTitles";
public static final String ENTITY_COUNT_CACHE = "entityCount";
public static final String ALARM_TYPES_CACHE = "alarmTypes";
}

2
dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmDao.java

@ -98,6 +98,6 @@ public interface AlarmDao extends Dao<Alarm> {
long countAlarmsByQuery(TenantId tenantId, CustomerId customerId, AlarmCountQuery query);
ListenableFuture<List<EntitySubtype>> findTenantAlarmTypesAsync(UUID tenantId);
List<EntitySubtype> findTenantAlarmTypesAsync(UUID tenantId);
}

26
dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmTypesCacheEvictEvent.java

@ -0,0 +1,26 @@
/**
* Copyright © 2016-2023 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.dao.alarm;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import org.thingsboard.server.common.data.id.TenantId;
@Data
@RequiredArgsConstructor
class AlarmTypesCacheEvictEvent {
private final TenantId tenantId;
}

36
dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmTypesCaffeineCache.java

@ -0,0 +1,36 @@
/**
* Copyright © 2016-2023 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.dao.alarm;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cache.CacheManager;
import org.springframework.stereotype.Service;
import org.thingsboard.server.cache.CaffeineTbTransactionalCache;
import org.thingsboard.server.common.data.CacheConstants;
import org.thingsboard.server.common.data.EntitySubtype;
import org.thingsboard.server.common.data.id.TenantId;
import java.util.ArrayList;
@ConditionalOnProperty(prefix = "cache", value = "type", havingValue = "caffeine", matchIfMissing = true)
@Service("AlarmTypesCache")
public class AlarmTypesCaffeineCache extends CaffeineTbTransactionalCache<TenantId, ArrayList<EntitySubtype>> {
public AlarmTypesCaffeineCache(CacheManager cacheManager) {
super(cacheManager, CacheConstants.ALARM_TYPES_CACHE);
}
}

38
dao/src/main/java/org/thingsboard/server/dao/alarm/AlarmTypesRedisCache.java

@ -0,0 +1,38 @@
/**
* Copyright © 2016-2023 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.dao.alarm;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.stereotype.Service;
import org.thingsboard.server.cache.CacheSpecsMap;
import org.thingsboard.server.cache.RedisTbTransactionalCache;
import org.thingsboard.server.cache.TBRedisCacheConfiguration;
import org.thingsboard.server.cache.TbFSTRedisSerializer;
import org.thingsboard.server.common.data.CacheConstants;
import org.thingsboard.server.common.data.EntitySubtype;
import org.thingsboard.server.common.data.id.TenantId;
import java.util.ArrayList;
@ConditionalOnProperty(prefix = "cache", value = "type", havingValue = "redis")
@Service("AlarmTypesCache")
public class AlarmTypesRedisCache extends RedisTbTransactionalCache<TenantId, ArrayList<EntitySubtype>> {
public AlarmTypesRedisCache(TBRedisCacheConfiguration configuration, CacheSpecsMap cacheSpecsMap, RedisConnectionFactory connectionFactory) {
super(CacheConstants.ALARM_TYPES_CACHE, cacheSpecsMap, connectionFactory, configuration, new TbFSTRedisSerializer<>());
}
}

35
dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java

@ -20,12 +20,14 @@ import com.fasterxml.jackson.databind.JsonNode;
import com.google.common.base.Function;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.event.TransactionalEventListener;
import org.springframework.util.CollectionUtils;
import org.thingsboard.server.cache.TbTransactionalCache;
import org.thingsboard.server.common.data.EntitySubtype;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.alarm.Alarm;
@ -56,7 +58,7 @@ import org.thingsboard.server.common.data.relation.EntityRelation;
import org.thingsboard.server.common.data.relation.EntityRelationsQuery;
import org.thingsboard.server.common.data.relation.EntitySearchDirection;
import org.thingsboard.server.common.data.relation.RelationsSearchParameters;
import org.thingsboard.server.dao.entity.AbstractEntityService;
import org.thingsboard.server.dao.entity.AbstractCachedEntityService;
import org.thingsboard.server.dao.entity.EntityService;
import org.thingsboard.server.dao.exception.DataValidationException;
import org.thingsboard.server.dao.service.ConstraintValidator;
@ -81,7 +83,7 @@ import static org.thingsboard.server.dao.service.Validator.validateId;
@Service("AlarmDaoService")
@Slf4j
@RequiredArgsConstructor
public class BaseAlarmService extends AbstractEntityService implements AlarmService {
public class BaseAlarmService extends AbstractCachedEntityService<TenantId, ArrayList<EntitySubtype>, AlarmTypesCacheEvictEvent> implements AlarmService {
public static final String INCORRECT_TENANT_ID = "Incorrect tenantId ";
@ -90,6 +92,17 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ
private final EntityService entityService;
private final DataValidator<Alarm> alarmDataValidator;
@Autowired
protected TbTransactionalCache<TenantId, ArrayList<EntitySubtype>> alarmTypesCache;
@TransactionalEventListener(classes = AlarmTypesCacheEvictEvent.class)
@Override
public void handleEvictEvent(AlarmTypesCacheEvictEvent event) {
TenantId tenantId = event.getTenantId();
cache.evict(tenantId);
alarmTypesCache.evict(tenantId);
}
@Override
public AlarmApiCallResult updateAlarm(AlarmUpdateRequest request) {
validateAlarmRequest(request);
@ -115,6 +128,7 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ
if (!result.isSuccessful() && !alarmCreationEnabled) {
throw new ApiUsageLimitsExceededException("Alarms creation is disabled");
}
publishEvictEvent(new AlarmTypesCacheEvictEvent(request.getTenantId()));
return withPropagated(result);
}
@ -191,6 +205,7 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ
} else {
deleteEntityRelations(tenantId, alarm.getId());
alarmDao.removeById(tenantId, alarm.getUuidId());
publishEvictEvent(new AlarmTypesCacheEvictEvent(tenantId));
return AlarmApiCallResult.builder().alarm(alarm).deleted(true).successful(true).build();
}
}
@ -206,12 +221,14 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ
AlarmOperationResult result = new AlarmOperationResult(alarm, true, new ArrayList<>(getPropagationEntityIds(alarm)));
deleteEntityRelations(tenantId, alarm.getId());
alarmDao.removeById(tenantId, alarm.getUuidId());
publishEvictEvent(new AlarmTypesCacheEvictEvent(tenantId));
return result;
}
private AlarmOperationResult createAlarm(Alarm alarm) throws InterruptedException, ExecutionException {
log.debug("New Alarm : {}", alarm);
Alarm saved = alarmDao.save(alarm.getTenantId(), alarm);
publishEvictEvent(new AlarmTypesCacheEvictEvent(alarm.getTenantId()));
List<EntityId> propagatedEntitiesList = createEntityAlarmRecords(saved);
return new AlarmOperationResult(saved, true, true, propagatedEntitiesList);
}
@ -380,15 +397,13 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ
}
@Override
public ListenableFuture<List<EntitySubtype>> findAlarmTypesByTenantId(TenantId tenantId) {
public List<EntitySubtype> findAlarmTypesByTenantId(TenantId tenantId) {
log.trace("Executing findAlarmTypesByTenantId, tenantId [{}]", tenantId);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
ListenableFuture<List<EntitySubtype>> tenantAssetTypes = alarmDao.findTenantAlarmTypesAsync(tenantId.getId());
return Futures.transform(tenantAssetTypes,
assetTypes -> {
assetTypes.sort(Comparator.comparing(EntitySubtype::getType));
return assetTypes;
}, MoreExecutors.directExecutor());
return cache.getAndPutInTransaction(tenantId, () ->
alarmDao.findTenantAlarmTypesAsync(tenantId.getId()).stream()
.sorted(Comparator.comparing(EntitySubtype::getType))
.collect(Collectors.toCollection(ArrayList::new)), false);
}
private Alarm merge(Alarm existing, Alarm alarm) {

2
dao/src/main/java/org/thingsboard/server/dao/sql/alarm/AlarmRepository.java

@ -346,6 +346,6 @@ public interface AlarmRepository extends JpaRepository<AlarmEntity, UUID> {
@Query(value = "SELECT unassign_alarm(:t_id, :a_id, :a_ts)", nativeQuery = true)
String unassignAlarm(@Param("t_id") UUID tenantId, @Param("a_id") UUID alarmId, @Param("a_ts") long unassignTime);
@Query("SELECT DISTINCT a.type FROM AlarmEntity a WHERE a.tenantId = :tenantId")
@Query(value = "SELECT DISTINCT a.type FROM alarm a WHERE a.tenant_id = :tenantId LIMIT 256", nativeQuery = true)
List<String> findTenantAlarmTypes(@Param("tenantId") UUID tenantId);
}

4
dao/src/main/java/org/thingsboard/server/dao/sql/alarm/JpaAlarmDao.java

@ -370,8 +370,8 @@ public class JpaAlarmDao extends JpaAbstractDao<AlarmEntity, Alarm> implements A
}
@Override
public ListenableFuture<List<EntitySubtype>> findTenantAlarmTypesAsync(UUID tenantId) {
return service.submit(() -> convertTenantEntityTypesToDto(tenantId, EntityType.ALARM, alarmRepository.findTenantAlarmTypes(tenantId)));
public List<EntitySubtype> findTenantAlarmTypesAsync(UUID tenantId) {
return convertTenantEntityTypesToDto(tenantId, EntityType.ALARM, alarmRepository.findTenantAlarmTypes(tenantId));
}
private static String getPropagationTypes(AlarmPropagationInfo ap) {

3
dao/src/test/resources/application-test.properties

@ -74,6 +74,9 @@ cache.specs.dashboardTitles.maxSize=10000
cache.specs.entityCount.timeToLiveInMinutes=1440
cache.specs.entityCount.maxSize=10000
cache.specs.alarmTypes.timeToLiveInMinutes=60
cache.specs.alarmTypes.maxSize=10000
redis.connection.host=localhost
redis.connection.port=6379
redis.connection.db=0

3
rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/RuleEngineAlarmService.java

@ -56,6 +56,7 @@ public interface RuleEngineAlarmService {
* Only one active alarm may exist for the pair {originatorId, alarmType}
*/
AlarmApiCallResult createAlarm(AlarmCreateOrUpdateActiveRequest request);
/**
* Designed to update existing alarm. Accepts only part of the alarm fields.
*/
@ -113,5 +114,5 @@ public interface RuleEngineAlarmService {
PageData<AlarmData> findAlarmDataByQueryForEntities(TenantId tenantId, AlarmDataQuery query, Collection<EntityId> orderedEntityIds);
ListenableFuture<List<EntitySubtype>> findAlarmTypesByTenantId(TenantId tenantId);
List<EntitySubtype> findAlarmTypesByTenantId(TenantId tenantId);
}

Loading…
Cancel
Save