|
|
@ -23,16 +23,18 @@ import org.springframework.beans.factory.annotation.Value; |
|
|
import org.springframework.context.annotation.Lazy; |
|
|
import org.springframework.context.annotation.Lazy; |
|
|
import org.springframework.data.util.Pair; |
|
|
import org.springframework.data.util.Pair; |
|
|
import org.springframework.stereotype.Service; |
|
|
import org.springframework.stereotype.Service; |
|
|
|
|
|
import org.thingsboard.server.common.data.ApiFeature; |
|
|
import org.thingsboard.server.common.data.ApiUsageRecordKey; |
|
|
import org.thingsboard.server.common.data.ApiUsageRecordKey; |
|
|
import org.thingsboard.server.common.data.ApiUsageState; |
|
|
import org.thingsboard.server.common.data.ApiUsageState; |
|
|
|
|
|
import org.thingsboard.server.common.data.ApiUsageStateValue; |
|
|
import org.thingsboard.server.common.data.Tenant; |
|
|
import org.thingsboard.server.common.data.Tenant; |
|
|
import org.thingsboard.server.common.data.TenantProfile; |
|
|
import org.thingsboard.server.common.data.TenantProfile; |
|
|
import org.thingsboard.server.common.data.id.ApiUsageStateId; |
|
|
import org.thingsboard.server.common.data.id.ApiUsageStateId; |
|
|
import org.thingsboard.server.common.data.id.TenantId; |
|
|
import org.thingsboard.server.common.data.id.TenantId; |
|
|
import org.thingsboard.server.common.data.id.TenantProfileId; |
|
|
import org.thingsboard.server.common.data.id.TenantProfileId; |
|
|
import org.thingsboard.server.common.data.kv.BasicTsKvEntry; |
|
|
import org.thingsboard.server.common.data.kv.BasicTsKvEntry; |
|
|
import org.thingsboard.server.common.data.kv.BooleanDataEntry; |
|
|
|
|
|
import org.thingsboard.server.common.data.kv.LongDataEntry; |
|
|
import org.thingsboard.server.common.data.kv.LongDataEntry; |
|
|
|
|
|
import org.thingsboard.server.common.data.kv.StringDataEntry; |
|
|
import org.thingsboard.server.common.data.kv.TsKvEntry; |
|
|
import org.thingsboard.server.common.data.kv.TsKvEntry; |
|
|
import org.thingsboard.server.common.data.page.PageDataIterable; |
|
|
import org.thingsboard.server.common.data.page.PageDataIterable; |
|
|
import org.thingsboard.server.common.data.tenant.profile.TenantProfileConfiguration; |
|
|
import org.thingsboard.server.common.data.tenant.profile.TenantProfileConfiguration; |
|
|
@ -57,8 +59,10 @@ import org.thingsboard.server.service.telemetry.InternalTelemetryService; |
|
|
import javax.annotation.PostConstruct; |
|
|
import javax.annotation.PostConstruct; |
|
|
import java.util.ArrayList; |
|
|
import java.util.ArrayList; |
|
|
import java.util.HashMap; |
|
|
import java.util.HashMap; |
|
|
|
|
|
import java.util.HashSet; |
|
|
import java.util.List; |
|
|
import java.util.List; |
|
|
import java.util.Map; |
|
|
import java.util.Map; |
|
|
|
|
|
import java.util.Set; |
|
|
import java.util.UUID; |
|
|
import java.util.UUID; |
|
|
import java.util.concurrent.ConcurrentHashMap; |
|
|
import java.util.concurrent.ConcurrentHashMap; |
|
|
import java.util.concurrent.ExecutionException; |
|
|
import java.util.concurrent.ExecutionException; |
|
|
@ -137,7 +141,7 @@ public class DefaultTbApiUsageStateService implements TbApiUsageStateService { |
|
|
TenantId tenantId = new TenantId(new UUID(statsMsg.getTenantIdMSB(), statsMsg.getTenantIdLSB())); |
|
|
TenantId tenantId = new TenantId(new UUID(statsMsg.getTenantIdMSB(), statsMsg.getTenantIdLSB())); |
|
|
TenantApiUsageState tenantState; |
|
|
TenantApiUsageState tenantState; |
|
|
List<TsKvEntry> updatedEntries; |
|
|
List<TsKvEntry> updatedEntries; |
|
|
Map<ApiFeature, Boolean> result = new HashMap<>(); |
|
|
Map<ApiFeature, ApiUsageStateValue> result; |
|
|
updateLock.lock(); |
|
|
updateLock.lock(); |
|
|
try { |
|
|
try { |
|
|
tenantState = getOrFetchState(tenantId); |
|
|
tenantState = getOrFetchState(tenantId); |
|
|
@ -148,17 +152,16 @@ public class DefaultTbApiUsageStateService implements TbApiUsageStateService { |
|
|
tenantState.setHour(newHourTs); |
|
|
tenantState.setHour(newHourTs); |
|
|
} |
|
|
} |
|
|
updatedEntries = new ArrayList<>(ApiUsageRecordKey.values().length); |
|
|
updatedEntries = new ArrayList<>(ApiUsageRecordKey.values().length); |
|
|
|
|
|
Set<ApiFeature> apiFeatures = new HashSet<>(); |
|
|
for (UsageStatsKVProto kvProto : statsMsg.getValuesList()) { |
|
|
for (UsageStatsKVProto kvProto : statsMsg.getValuesList()) { |
|
|
ApiUsageRecordKey recordKey = ApiUsageRecordKey.valueOf(kvProto.getKey()); |
|
|
ApiUsageRecordKey recordKey = ApiUsageRecordKey.valueOf(kvProto.getKey()); |
|
|
long newValue = tenantState.add(recordKey, kvProto.getValue()); |
|
|
long newValue = tenantState.add(recordKey, kvProto.getValue()); |
|
|
updatedEntries.add(new BasicTsKvEntry(ts, new LongDataEntry(recordKey.getApiCountKey(), newValue))); |
|
|
updatedEntries.add(new BasicTsKvEntry(ts, new LongDataEntry(recordKey.getApiCountKey(), newValue))); |
|
|
long newHourlyValue = tenantState.addToHourly(recordKey, kvProto.getValue()); |
|
|
long newHourlyValue = tenantState.addToHourly(recordKey, kvProto.getValue()); |
|
|
updatedEntries.add(new BasicTsKvEntry(hourTs, new LongDataEntry(recordKey.getApiCountKey() + HOURLY, newHourlyValue))); |
|
|
updatedEntries.add(new BasicTsKvEntry(hourTs, new LongDataEntry(recordKey.getApiCountKey() + HOURLY, newHourlyValue))); |
|
|
Pair<ApiFeature, Boolean> update = tenantState.checkStateUpdatedDueToThreshold(recordKey); |
|
|
apiFeatures.add(recordKey.getApiFeature()); |
|
|
if (update != null) { |
|
|
|
|
|
result.put(update.getFirst(), update.getSecond()); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
result = tenantState.checkStateUpdatedDueToThreshold(apiFeatures); |
|
|
} finally { |
|
|
} finally { |
|
|
updateLock.unlock(); |
|
|
updateLock.unlock(); |
|
|
} |
|
|
} |
|
|
@ -196,7 +199,9 @@ public class DefaultTbApiUsageStateService implements TbApiUsageStateService { |
|
|
state = otherTenantStates.get(tenantId); |
|
|
state = otherTenantStates.get(tenantId); |
|
|
if (state == null) { |
|
|
if (state == null) { |
|
|
state = apiUsageStateService.findTenantApiUsageState(tenantId); |
|
|
state = apiUsageStateService.findTenantApiUsageState(tenantId); |
|
|
otherTenantStates.put(tenantId, state); |
|
|
if (state != null) { |
|
|
|
|
|
otherTenantStates.put(tenantId, state); |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
} finally { |
|
|
} finally { |
|
|
updateLock.unlock(); |
|
|
updateLock.unlock(); |
|
|
@ -245,7 +250,7 @@ public class DefaultTbApiUsageStateService implements TbApiUsageStateService { |
|
|
TenantProfileData oldProfileData = state.getTenantProfileData(); |
|
|
TenantProfileData oldProfileData = state.getTenantProfileData(); |
|
|
state.setTenantProfileId(tenantProfile.getId()); |
|
|
state.setTenantProfileId(tenantProfile.getId()); |
|
|
state.setTenantProfileData(tenantProfile.getProfileData()); |
|
|
state.setTenantProfileData(tenantProfile.getProfileData()); |
|
|
Map<ApiFeature, Boolean> result = state.checkStateUpdatedDueToThresholds(); |
|
|
Map<ApiFeature, ApiUsageStateValue> result = state.checkStateUpdatedDueToThresholds(); |
|
|
if (!result.isEmpty()) { |
|
|
if (!result.isEmpty()) { |
|
|
persistAndNotify(state, result); |
|
|
persistAndNotify(state, result); |
|
|
} |
|
|
} |
|
|
@ -269,14 +274,15 @@ public class DefaultTbApiUsageStateService implements TbApiUsageStateService { |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
private void persistAndNotify(TenantApiUsageState state, Map<ApiFeature, Boolean> result) { |
|
|
private void persistAndNotify(TenantApiUsageState state, Map<ApiFeature, ApiUsageStateValue> result) { |
|
|
log.info("[{}] Detected update of the API state: {}", state.getTenantId(), result); |
|
|
log.info("[{}] Detected update of the API state: {}", state.getTenantId(), result); |
|
|
apiUsageStateService.update(state.getApiUsageState()); |
|
|
apiUsageStateService.update(state.getApiUsageState()); |
|
|
clusterService.onApiStateChange(state.getApiUsageState(), null); |
|
|
clusterService.onApiStateChange(state.getApiUsageState(), null); |
|
|
long ts = System.currentTimeMillis(); |
|
|
long ts = System.currentTimeMillis(); |
|
|
List<TsKvEntry> stateTelemetry = new ArrayList<>(); |
|
|
List<TsKvEntry> stateTelemetry = new ArrayList<>(); |
|
|
result.forEach(((apiFeature, aState) -> stateTelemetry.add(new BasicTsKvEntry(ts, new BooleanDataEntry(apiFeature.getApiStateKey(), aState))))); |
|
|
result.forEach(((apiFeature, aState) -> stateTelemetry.add(new BasicTsKvEntry(ts, new StringDataEntry(apiFeature.getApiStateKey(), aState.name()))))); |
|
|
tsWsService.saveAndNotifyInternal(state.getTenantId(), state.getApiUsageState().getId(), stateTelemetry, VOID_CALLBACK); |
|
|
tsWsService.saveAndNotifyInternal(state.getTenantId(), state.getApiUsageState().getId(), stateTelemetry, VOID_CALLBACK); |
|
|
|
|
|
//TODO: notify tenant admin via email!
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
private void checkStartOfNextCycle() { |
|
|
private void checkStartOfNextCycle() { |
|
|
|