Implement created alarms limiting
This commit is contained in:
parent
a7d1b54bb4
commit
9873115d8b
@ -130,3 +130,7 @@ DO $$
|
||||
END;
|
||||
$$;
|
||||
|
||||
|
||||
ALTER TABLE api_usage_state
|
||||
ADD COLUMN IF NOT EXISTS alarm_exec VARCHAR(32);
|
||||
UPDATE api_usage_state SET alarm_exec = 'ENABLED' WHERE alarm_exec IS NULL;
|
||||
|
||||
@ -106,6 +106,8 @@ public abstract class BaseApiUsageState {
|
||||
return apiUsageState.getEmailExecState();
|
||||
case SMS:
|
||||
return apiUsageState.getSmsExecState();
|
||||
case ALARM:
|
||||
return apiUsageState.getAlarmExecState();
|
||||
default:
|
||||
return ApiUsageStateValue.ENABLED;
|
||||
}
|
||||
@ -132,6 +134,9 @@ public abstract class BaseApiUsageState {
|
||||
case SMS:
|
||||
apiUsageState.setSmsExecState(value);
|
||||
break;
|
||||
case ALARM:
|
||||
apiUsageState.setAlarmExecState(value);
|
||||
break;
|
||||
}
|
||||
return !currentValue.equals(value);
|
||||
}
|
||||
|
||||
@ -309,6 +309,8 @@ public class DefaultMailService implements MailService {
|
||||
case EMAIL:
|
||||
case SMS:
|
||||
return "send";
|
||||
case ALARM:
|
||||
return "create";
|
||||
default:
|
||||
throw new RuntimeException("Not implemented!");
|
||||
}
|
||||
@ -327,6 +329,8 @@ public class DefaultMailService implements MailService {
|
||||
case EMAIL:
|
||||
case SMS:
|
||||
return "sent";
|
||||
case ALARM:
|
||||
return "created";
|
||||
default:
|
||||
throw new RuntimeException("Not implemented!");
|
||||
}
|
||||
|
||||
@ -23,6 +23,7 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.thingsboard.server.common.data.ApiUsageRecordKey;
|
||||
import org.thingsboard.server.common.data.alarm.Alarm;
|
||||
import org.thingsboard.server.common.data.alarm.AlarmInfo;
|
||||
import org.thingsboard.server.common.data.alarm.AlarmQuery;
|
||||
@ -43,6 +44,8 @@ import org.thingsboard.server.dao.alarm.AlarmOperationResult;
|
||||
import org.thingsboard.server.dao.alarm.AlarmService;
|
||||
import org.thingsboard.server.gen.transport.TransportProtos;
|
||||
import org.thingsboard.server.queue.discovery.PartitionService;
|
||||
import org.thingsboard.server.queue.usagestats.TbApiUsageClient;
|
||||
import org.thingsboard.server.service.apiusage.TbApiUsageStateService;
|
||||
import org.thingsboard.server.service.queue.TbClusterService;
|
||||
import org.thingsboard.server.service.subscription.SubscriptionManagerService;
|
||||
import org.thingsboard.server.service.subscription.TbSubscriptionUtils;
|
||||
@ -58,12 +61,18 @@ import java.util.Optional;
|
||||
public class DefaultAlarmSubscriptionService extends AbstractSubscriptionService implements AlarmSubscriptionService {
|
||||
|
||||
private final AlarmService alarmService;
|
||||
private final TbApiUsageClient apiUsageClient;
|
||||
private final TbApiUsageStateService apiUsageStateService;
|
||||
|
||||
public DefaultAlarmSubscriptionService(TbClusterService clusterService,
|
||||
PartitionService partitionService,
|
||||
AlarmService alarmService) {
|
||||
AlarmService alarmService,
|
||||
TbApiUsageClient apiUsageClient,
|
||||
TbApiUsageStateService apiUsageStateService) {
|
||||
super(clusterService, partitionService);
|
||||
this.alarmService = alarmService;
|
||||
this.apiUsageClient = apiUsageClient;
|
||||
this.apiUsageStateService = apiUsageStateService;
|
||||
}
|
||||
|
||||
@Autowired(required = false)
|
||||
@ -78,10 +87,19 @@ public class DefaultAlarmSubscriptionService extends AbstractSubscriptionService
|
||||
|
||||
@Override
|
||||
public Alarm createOrUpdateAlarm(Alarm alarm) {
|
||||
AlarmOperationResult result = alarmService.createOrUpdateAlarm(alarm);
|
||||
AlarmOperationResult result = alarmService.createOrUpdateAlarm(alarm,
|
||||
() -> {
|
||||
if (!apiUsageStateService.getApiUsageState(alarm.getTenantId()).isAlarmCreationEnabled()) {
|
||||
throw new IllegalStateException("Alarms creation is disabled due to API limits");
|
||||
}
|
||||
},
|
||||
() -> {});
|
||||
if (result.isSuccessful()) {
|
||||
onAlarmUpdated(result);
|
||||
}
|
||||
if (result.isCreated()) {
|
||||
apiUsageClient.report(alarm.getTenantId(), null, ApiUsageRecordKey.CREATED_ALARMS_COUNT);
|
||||
}
|
||||
return result.getAlarm();
|
||||
}
|
||||
|
||||
|
||||
@ -26,17 +26,21 @@ import java.util.List;
|
||||
public class AlarmOperationResult {
|
||||
private final Alarm alarm;
|
||||
private final boolean successful;
|
||||
private final boolean created;
|
||||
private final List<EntityId> propagatedEntitiesList;
|
||||
|
||||
public AlarmOperationResult(Alarm alarm, boolean successful) {
|
||||
this.alarm = alarm;
|
||||
this.successful = successful;
|
||||
this.propagatedEntitiesList = Collections.emptyList();
|
||||
this(alarm, successful, Collections.emptyList());
|
||||
}
|
||||
|
||||
public AlarmOperationResult(Alarm alarm, boolean successful, List<EntityId> propagatedEntitiesList) {
|
||||
this(alarm, successful, false, propagatedEntitiesList);
|
||||
}
|
||||
|
||||
public AlarmOperationResult(Alarm alarm, boolean successful, boolean created, List<EntityId> propagatedEntitiesList) {
|
||||
this.alarm = alarm;
|
||||
this.successful = successful;
|
||||
this.created = created;
|
||||
this.propagatedEntitiesList = propagatedEntitiesList;
|
||||
}
|
||||
}
|
||||
|
||||
@ -31,6 +31,7 @@ import org.thingsboard.server.common.data.page.PageData;
|
||||
import org.thingsboard.server.common.data.query.AlarmData;
|
||||
import org.thingsboard.server.common.data.query.AlarmDataPageLink;
|
||||
import org.thingsboard.server.common.data.query.AlarmDataQuery;
|
||||
import org.thingsboard.server.common.msg.queue.TbCallback;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
@ -41,6 +42,8 @@ public interface AlarmService {
|
||||
|
||||
AlarmOperationResult createOrUpdateAlarm(Alarm alarm);
|
||||
|
||||
AlarmOperationResult createOrUpdateAlarm(Alarm alarm, Runnable onAlarmCreation, Runnable onAlarmUpdate);
|
||||
|
||||
AlarmOperationResult deleteAlarm(TenantId tenantId, AlarmId alarmId);
|
||||
|
||||
ListenableFuture<AlarmOperationResult> ackAlarm(TenantId tenantId, AlarmId alarmId, long ackTs);
|
||||
|
||||
@ -23,7 +23,8 @@ public enum ApiFeature {
|
||||
RE("ruleEngineApiState", "Rule Engine execution"),
|
||||
JS("jsExecutionApiState", "JavaScript functions execution"),
|
||||
EMAIL("emailApiState", "Email messages"),
|
||||
SMS("smsApiState", "SMS messages");
|
||||
SMS("smsApiState", "SMS messages"),
|
||||
ALARM("alarmApiState", "Created alarms");
|
||||
|
||||
@Getter
|
||||
private final String apiStateKey;
|
||||
|
||||
@ -25,13 +25,16 @@ public enum ApiUsageRecordKey {
|
||||
RE_EXEC_COUNT(ApiFeature.RE, "ruleEngineExecutionCount", "ruleEngineExecutionLimit"),
|
||||
JS_EXEC_COUNT(ApiFeature.JS, "jsExecutionCount", "jsExecutionLimit"),
|
||||
EMAIL_EXEC_COUNT(ApiFeature.EMAIL, "emailCount", "emailLimit"),
|
||||
SMS_EXEC_COUNT(ApiFeature.SMS, "smsCount", "smsLimit");
|
||||
SMS_EXEC_COUNT(ApiFeature.SMS, "smsCount", "smsLimit"),
|
||||
CREATED_ALARMS_COUNT(ApiFeature.ALARM, "createdAlarmsCount", "createdAlarmsLimit");
|
||||
|
||||
private static final ApiUsageRecordKey[] JS_RECORD_KEYS = {JS_EXEC_COUNT};
|
||||
private static final ApiUsageRecordKey[] RE_RECORD_KEYS = {RE_EXEC_COUNT};
|
||||
private static final ApiUsageRecordKey[] DB_RECORD_KEYS = {STORAGE_DP_COUNT};
|
||||
private static final ApiUsageRecordKey[] TRANSPORT_RECORD_KEYS = {TRANSPORT_MSG_COUNT, TRANSPORT_DP_COUNT};
|
||||
private static final ApiUsageRecordKey[] EMAIL_RECORD_KEYS = {EMAIL_EXEC_COUNT};
|
||||
private static final ApiUsageRecordKey[] SMS_RECORD_KEYS = {SMS_EXEC_COUNT};
|
||||
private static final ApiUsageRecordKey[] ALARM_RECORD_KEYS = {CREATED_ALARMS_COUNT};
|
||||
|
||||
@Getter
|
||||
private final ApiFeature apiFeature;
|
||||
@ -60,6 +63,8 @@ public enum ApiUsageRecordKey {
|
||||
return EMAIL_RECORD_KEYS;
|
||||
case SMS:
|
||||
return SMS_RECORD_KEYS;
|
||||
case ALARM:
|
||||
return ALARM_RECORD_KEYS;
|
||||
default:
|
||||
return new ApiUsageRecordKey[]{};
|
||||
}
|
||||
|
||||
@ -25,34 +25,21 @@ import org.thingsboard.server.common.data.id.ApiUsageStateId;
|
||||
|
||||
@ToString
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Getter
|
||||
@Setter
|
||||
public class ApiUsageState extends BaseData<ApiUsageStateId> implements HasTenantId {
|
||||
|
||||
private static final long serialVersionUID = 8250339805336035966L;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private TenantId tenantId;
|
||||
@Getter
|
||||
@Setter
|
||||
private EntityId entityId;
|
||||
@Getter
|
||||
@Setter
|
||||
private ApiUsageStateValue transportState;
|
||||
@Getter
|
||||
@Setter
|
||||
private ApiUsageStateValue dbStorageState;
|
||||
@Getter
|
||||
@Setter
|
||||
private ApiUsageStateValue reExecState;
|
||||
@Getter
|
||||
@Setter
|
||||
private ApiUsageStateValue jsExecState;
|
||||
@Getter
|
||||
@Setter
|
||||
private ApiUsageStateValue emailExecState;
|
||||
@Getter
|
||||
@Setter
|
||||
private ApiUsageStateValue smsExecState;
|
||||
private ApiUsageStateValue alarmExecState;
|
||||
|
||||
public ApiUsageState() {
|
||||
super();
|
||||
@ -72,6 +59,7 @@ public class ApiUsageState extends BaseData<ApiUsageStateId> implements HasTenan
|
||||
this.jsExecState = ur.getJsExecState();
|
||||
this.emailExecState = ur.getEmailExecState();
|
||||
this.smsExecState = ur.getSmsExecState();
|
||||
this.alarmExecState = ur.getAlarmExecState();
|
||||
}
|
||||
|
||||
public boolean isTransportEnabled() {
|
||||
@ -97,4 +85,8 @@ public class ApiUsageState extends BaseData<ApiUsageStateId> implements HasTenan
|
||||
public boolean isSmsSendEnabled(){
|
||||
return !ApiUsageStateValue.DISABLED.equals(smsExecState);
|
||||
}
|
||||
|
||||
public boolean isAlarmCreationEnabled() {
|
||||
return alarmExecState != ApiUsageStateValue.DISABLED;
|
||||
}
|
||||
}
|
||||
|
||||
@ -50,6 +50,7 @@ public class DefaultTenantProfileConfiguration implements TenantProfileConfigura
|
||||
private int maxRuleNodeExecutionsPerMessage;
|
||||
private long maxEmails;
|
||||
private long maxSms;
|
||||
private long maxCreatedAlarms;
|
||||
|
||||
private int defaultStorageTtlDays;
|
||||
|
||||
@ -72,6 +73,8 @@ public class DefaultTenantProfileConfiguration implements TenantProfileConfigura
|
||||
return maxEmails;
|
||||
case SMS_EXEC_COUNT:
|
||||
return maxSms;
|
||||
case CREATED_ALARMS_COUNT:
|
||||
return maxCreatedAlarms;
|
||||
}
|
||||
return 0L;
|
||||
}
|
||||
|
||||
@ -47,6 +47,7 @@ import org.thingsboard.server.common.data.relation.EntityRelationsQuery;
|
||||
import org.thingsboard.server.common.data.relation.EntitySearchDirection;
|
||||
import org.thingsboard.server.common.data.relation.RelationTypeGroup;
|
||||
import org.thingsboard.server.common.data.relation.RelationsSearchParameters;
|
||||
import org.thingsboard.server.common.msg.queue.TbCallback;
|
||||
import org.thingsboard.server.dao.entity.AbstractEntityService;
|
||||
import org.thingsboard.server.dao.entity.EntityService;
|
||||
import org.thingsboard.server.dao.exception.DataValidationException;
|
||||
@ -65,6 +66,7 @@ import java.util.Set;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@ -102,6 +104,11 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ
|
||||
|
||||
@Override
|
||||
public AlarmOperationResult createOrUpdateAlarm(Alarm alarm) {
|
||||
return createOrUpdateAlarm(alarm, () -> {}, () -> {});
|
||||
}
|
||||
|
||||
@Override
|
||||
public AlarmOperationResult createOrUpdateAlarm(Alarm alarm, Runnable onAlarmCreation, Runnable onAlarmUpdate) {
|
||||
alarmDataValidator.validate(alarm, Alarm::getTenantId);
|
||||
try {
|
||||
if (alarm.getStartTs() == 0L) {
|
||||
@ -114,11 +121,14 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ
|
||||
if (alarm.getId() == null) {
|
||||
Alarm existing = alarmDao.findLatestByOriginatorAndType(alarm.getTenantId(), alarm.getOriginator(), alarm.getType()).get();
|
||||
if (existing == null || existing.getStatus().isCleared()) {
|
||||
onAlarmCreation.run();
|
||||
return createAlarm(alarm);
|
||||
} else {
|
||||
onAlarmUpdate.run();
|
||||
return updateAlarm(existing, alarm);
|
||||
}
|
||||
} else {
|
||||
onAlarmUpdate.run();
|
||||
return updateAlarm(alarm).get();
|
||||
}
|
||||
} catch (ExecutionException | InterruptedException e) {
|
||||
@ -159,7 +169,7 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ
|
||||
log.debug("New Alarm : {}", alarm);
|
||||
Alarm saved = alarmDao.save(alarm.getTenantId(), alarm);
|
||||
List<EntityId> propagatedEntitiesList = createAlarmRelations(saved);
|
||||
return new AlarmOperationResult(saved, true, propagatedEntitiesList);
|
||||
return new AlarmOperationResult(saved, true, true, propagatedEntitiesList);
|
||||
}
|
||||
|
||||
private List<EntityId> createAlarmRelations(Alarm alarm) throws InterruptedException, ExecutionException {
|
||||
|
||||
@ -465,6 +465,7 @@ public class ModelConstants {
|
||||
public static final String API_USAGE_STATE_JS_EXEC_COLUMN = "js_exec";
|
||||
public static final String API_USAGE_STATE_EMAIL_EXEC_COLUMN = "email_exec";
|
||||
public static final String API_USAGE_STATE_SMS_EXEC_COLUMN = "sms_exec";
|
||||
public static final String API_USAGE_STATE_ALARM_EXEC_COLUMN = "alarm_exec";
|
||||
|
||||
/**
|
||||
* Resource constants.
|
||||
|
||||
@ -69,6 +69,9 @@ public class ApiUsageStateEntity extends BaseSqlEntity<ApiUsageState> implements
|
||||
@Enumerated(EnumType.STRING)
|
||||
@Column(name = ModelConstants.API_USAGE_STATE_SMS_EXEC_COLUMN)
|
||||
private ApiUsageStateValue smsExecState = ApiUsageStateValue.ENABLED;
|
||||
@Enumerated(EnumType.STRING)
|
||||
@Column(name = ModelConstants.API_USAGE_STATE_ALARM_EXEC_COLUMN)
|
||||
private ApiUsageStateValue alarmExecState = ApiUsageStateValue.ENABLED;
|
||||
|
||||
public ApiUsageStateEntity() {
|
||||
}
|
||||
@ -91,6 +94,7 @@ public class ApiUsageStateEntity extends BaseSqlEntity<ApiUsageState> implements
|
||||
this.jsExecState = ur.getJsExecState();
|
||||
this.emailExecState = ur.getEmailExecState();
|
||||
this.smsExecState = ur.getSmsExecState();
|
||||
this.alarmExecState = ur.getAlarmExecState();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -109,6 +113,7 @@ public class ApiUsageStateEntity extends BaseSqlEntity<ApiUsageState> implements
|
||||
ur.setJsExecState(jsExecState);
|
||||
ur.setEmailExecState(emailExecState);
|
||||
ur.setSmsExecState(smsExecState);
|
||||
ur.setAlarmExecState(alarmExecState);
|
||||
return ur;
|
||||
}
|
||||
|
||||
|
||||
@ -90,6 +90,7 @@ public class ApiUsageStateServiceImpl extends AbstractEntityService implements A
|
||||
apiUsageState.setDbStorageState(ApiUsageStateValue.ENABLED);
|
||||
apiUsageState.setSmsExecState(ApiUsageStateValue.ENABLED);
|
||||
apiUsageState.setEmailExecState(ApiUsageStateValue.ENABLED);
|
||||
apiUsageState.setAlarmExecState(ApiUsageStateValue.ENABLED);
|
||||
apiUsageStateValidator.validate(apiUsageState, ApiUsageState::getTenantId);
|
||||
|
||||
ApiUsageState saved = apiUsageStateDao.save(apiUsageState.getTenantId(), apiUsageState);
|
||||
@ -107,6 +108,8 @@ public class ApiUsageStateServiceImpl extends AbstractEntityService implements A
|
||||
new StringDataEntry(ApiFeature.EMAIL.getApiStateKey(), ApiUsageStateValue.ENABLED.name())));
|
||||
apiUsageStates.add(new BasicTsKvEntry(saved.getCreatedTime(),
|
||||
new StringDataEntry(ApiFeature.SMS.getApiStateKey(), ApiUsageStateValue.ENABLED.name())));
|
||||
apiUsageStates.add(new BasicTsKvEntry(saved.getCreatedTime(),
|
||||
new StringDataEntry(ApiFeature.ALARM.getApiStateKey(), ApiUsageStateValue.ENABLED.name())));
|
||||
tsService.save(tenantId, saved.getId(), apiUsageStates, 0L);
|
||||
|
||||
if (entityId.getEntityType() == EntityType.TENANT && !entityId.equals(TenantId.SYS_TENANT_ID)) {
|
||||
|
||||
@ -454,6 +454,7 @@ CREATE TABLE IF NOT EXISTS api_usage_state (
|
||||
js_exec varchar(32),
|
||||
email_exec varchar(32),
|
||||
sms_exec varchar(32),
|
||||
alarm_exec varchar(32),
|
||||
CONSTRAINT api_usage_state_unq_key UNIQUE (tenant_id, entity_id)
|
||||
);
|
||||
|
||||
|
||||
@ -491,6 +491,7 @@ CREATE TABLE IF NOT EXISTS api_usage_state (
|
||||
js_exec varchar(32),
|
||||
email_exec varchar(32),
|
||||
sms_exec varchar(32),
|
||||
alarm_exec varchar(32),
|
||||
CONSTRAINT api_usage_state_unq_key UNIQUE (tenant_id, entity_id)
|
||||
);
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user