|
|
@ -29,10 +29,13 @@ 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.ApiUsageStateMailMessage; |
|
|
import org.thingsboard.server.common.data.ApiUsageStateMailMessage; |
|
|
import org.thingsboard.server.common.data.ApiUsageStateValue; |
|
|
import org.thingsboard.server.common.data.ApiUsageStateValue; |
|
|
|
|
|
import org.thingsboard.server.common.data.EntityType; |
|
|
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.exception.ThingsboardException; |
|
|
import org.thingsboard.server.common.data.exception.ThingsboardException; |
|
|
import org.thingsboard.server.common.data.id.ApiUsageStateId; |
|
|
import org.thingsboard.server.common.data.id.ApiUsageStateId; |
|
|
|
|
|
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.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; |
|
|
@ -66,6 +69,7 @@ import java.util.Arrays; |
|
|
import java.util.HashSet; |
|
|
import java.util.HashSet; |
|
|
import java.util.List; |
|
|
import java.util.List; |
|
|
import java.util.Map; |
|
|
import java.util.Map; |
|
|
|
|
|
import java.util.Optional; |
|
|
import java.util.Set; |
|
|
import java.util.Set; |
|
|
import java.util.UUID; |
|
|
import java.util.UUID; |
|
|
import java.util.concurrent.ConcurrentHashMap; |
|
|
import java.util.concurrent.ConcurrentHashMap; |
|
|
@ -106,9 +110,9 @@ public class DefaultTbApiUsageStateService extends TbApplicationEventListener<Pa |
|
|
private InternalTelemetryService tsWsService; |
|
|
private InternalTelemetryService tsWsService; |
|
|
|
|
|
|
|
|
// Tenants that should be processed on this server
|
|
|
// Tenants that should be processed on this server
|
|
|
private final Map<TenantId, TenantApiUsageState> myTenantStates = new ConcurrentHashMap<>(); |
|
|
private final Map<EntityId, BaseApiUsageState> myUsageStates = new ConcurrentHashMap<>(); |
|
|
// Tenants that should be processed on other servers
|
|
|
// Tenants that should be processed on other servers
|
|
|
private final Map<TenantId, ApiUsageState> otherTenantStates = new ConcurrentHashMap<>(); |
|
|
private final Map<EntityId, ApiUsageState> otherUsageStates = new ConcurrentHashMap<>(); |
|
|
|
|
|
|
|
|
@Value("${usage.stats.report.enabled:true}") |
|
|
@Value("${usage.stats.report.enabled:true}") |
|
|
private boolean enabled; |
|
|
private boolean enabled; |
|
|
@ -151,60 +155,73 @@ public class DefaultTbApiUsageStateService extends TbApplicationEventListener<Pa |
|
|
public void process(TbProtoQueueMsg<ToUsageStatsServiceMsg> msg, TbCallback callback) { |
|
|
public void process(TbProtoQueueMsg<ToUsageStatsServiceMsg> msg, TbCallback callback) { |
|
|
ToUsageStatsServiceMsg statsMsg = msg.getValue(); |
|
|
ToUsageStatsServiceMsg statsMsg = msg.getValue(); |
|
|
TenantId tenantId = new TenantId(new UUID(statsMsg.getTenantIdMSB(), statsMsg.getTenantIdLSB())); |
|
|
TenantId tenantId = new TenantId(new UUID(statsMsg.getTenantIdMSB(), statsMsg.getTenantIdLSB())); |
|
|
|
|
|
CustomerId customerId; |
|
|
if (tenantProfileCache.get(tenantId) == null) { |
|
|
if (statsMsg.getCustomerIdMSB() != 0 && statsMsg.getCustomerIdLSB() != 0) { |
|
|
return; |
|
|
customerId = new CustomerId(new UUID(statsMsg.getCustomerIdMSB(), statsMsg.getCustomerIdLSB())); |
|
|
|
|
|
} else { |
|
|
|
|
|
customerId = new CustomerId(EntityId.NULL_UUID); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
TenantApiUsageState tenantState; |
|
|
processEntityUsageStats(tenantId, customerId.isNullUid() ? tenantId : customerId, statsMsg.getValuesList()); |
|
|
|
|
|
callback.onSuccess(); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private void processEntityUsageStats(TenantId tenantId, EntityId entityId, List<UsageStatsKVProto> values) { |
|
|
|
|
|
if (tenantProfileCache.get(tenantId) == null) return; |
|
|
|
|
|
|
|
|
|
|
|
BaseApiUsageState usageState; |
|
|
List<TsKvEntry> updatedEntries; |
|
|
List<TsKvEntry> updatedEntries; |
|
|
Map<ApiFeature, ApiUsageStateValue> result; |
|
|
Map<ApiFeature, ApiUsageStateValue> result; |
|
|
|
|
|
|
|
|
updateLock.lock(); |
|
|
updateLock.lock(); |
|
|
try { |
|
|
try { |
|
|
tenantState = getOrFetchState(tenantId); |
|
|
usageState = getOrFetchState(tenantId, entityId); |
|
|
long ts = tenantState.getCurrentCycleTs(); |
|
|
long ts = usageState.getCurrentCycleTs(); |
|
|
long hourTs = tenantState.getCurrentHourTs(); |
|
|
long hourTs = usageState.getCurrentHourTs(); |
|
|
long newHourTs = SchedulerUtils.getStartOfCurrentHour(); |
|
|
long newHourTs = SchedulerUtils.getStartOfCurrentHour(); |
|
|
if (newHourTs != hourTs) { |
|
|
if (newHourTs != hourTs) { |
|
|
tenantState.setHour(newHourTs); |
|
|
usageState.setHour(newHourTs); |
|
|
} |
|
|
} |
|
|
updatedEntries = new ArrayList<>(ApiUsageRecordKey.values().length); |
|
|
updatedEntries = new ArrayList<>(ApiUsageRecordKey.values().length); |
|
|
Set<ApiFeature> apiFeatures = new HashSet<>(); |
|
|
Set<ApiFeature> apiFeatures = new HashSet<>(); |
|
|
for (UsageStatsKVProto kvProto : statsMsg.getValuesList()) { |
|
|
for (UsageStatsKVProto kvProto : values) { |
|
|
ApiUsageRecordKey recordKey = ApiUsageRecordKey.valueOf(kvProto.getKey()); |
|
|
ApiUsageRecordKey recordKey = ApiUsageRecordKey.valueOf(kvProto.getKey()); |
|
|
long newValue = tenantState.add(recordKey, kvProto.getValue()); |
|
|
long newValue = usageState.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 = usageState.addToHourly(recordKey, kvProto.getValue()); |
|
|
updatedEntries.add(new BasicTsKvEntry(newHourTs, new LongDataEntry(recordKey.getApiCountKey() + HOURLY, newHourlyValue))); |
|
|
updatedEntries.add(new BasicTsKvEntry(newHourTs, new LongDataEntry(recordKey.getApiCountKey() + HOURLY, newHourlyValue))); |
|
|
apiFeatures.add(recordKey.getApiFeature()); |
|
|
apiFeatures.add(recordKey.getApiFeature()); |
|
|
} |
|
|
} |
|
|
result = tenantState.checkStateUpdatedDueToThreshold(apiFeatures); |
|
|
result = usageState.checkStateUpdatedDueToThreshold(apiFeatures); |
|
|
} finally { |
|
|
} finally { |
|
|
updateLock.unlock(); |
|
|
updateLock.unlock(); |
|
|
} |
|
|
} |
|
|
tsWsService.saveAndNotifyInternal(tenantId, tenantState.getApiUsageState().getId(), updatedEntries, VOID_CALLBACK); |
|
|
tsWsService.saveAndNotifyInternal(tenantId, usageState.getApiUsageState().getId(), updatedEntries, VOID_CALLBACK); |
|
|
if (!result.isEmpty()) { |
|
|
if (!result.isEmpty()) { |
|
|
persistAndNotify(tenantState, result); |
|
|
persistAndNotify(usageState, result); |
|
|
} |
|
|
} |
|
|
callback.onSuccess(); |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@Override |
|
|
@Override |
|
|
protected void onTbApplicationEvent(PartitionChangeEvent partitionChangeEvent) { |
|
|
protected void onTbApplicationEvent(PartitionChangeEvent partitionChangeEvent) { |
|
|
if (partitionChangeEvent.getServiceType().equals(ServiceType.TB_CORE)) { |
|
|
if (partitionChangeEvent.getServiceType().equals(ServiceType.TB_CORE)) { |
|
|
myTenantStates.entrySet().removeIf(entry -> !partitionService.resolve(ServiceType.TB_CORE, entry.getKey(), entry.getKey()).isMyPartition()); |
|
|
myUsageStates.entrySet().removeIf(entry -> { |
|
|
otherTenantStates.entrySet().removeIf(entry -> partitionService.resolve(ServiceType.TB_CORE, entry.getKey(), entry.getKey()).isMyPartition()); |
|
|
return !partitionService.resolve(ServiceType.TB_CORE, entry.getValue().getTenantId(), entry.getKey()).isMyPartition(); |
|
|
|
|
|
}); |
|
|
|
|
|
otherUsageStates.entrySet().removeIf(entry -> { |
|
|
|
|
|
return partitionService.resolve(ServiceType.TB_CORE, entry.getValue().getTenantId(), entry.getKey()).isMyPartition(); |
|
|
|
|
|
}); |
|
|
initStatesFromDataBase(); |
|
|
initStatesFromDataBase(); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@Override |
|
|
@Override |
|
|
public ApiUsageState getApiUsageState(TenantId tenantId) { |
|
|
public ApiUsageState getApiUsageState(TenantId tenantId) { |
|
|
TenantApiUsageState tenantState = myTenantStates.get(tenantId); |
|
|
TenantApiUsageState tenantState = (TenantApiUsageState) myUsageStates.get(tenantId); |
|
|
if (tenantState != null) { |
|
|
if (tenantState != null) { |
|
|
return tenantState.getApiUsageState(); |
|
|
return tenantState.getApiUsageState(); |
|
|
} else { |
|
|
} else { |
|
|
ApiUsageState state = otherTenantStates.get(tenantId); |
|
|
ApiUsageState state = otherUsageStates.get(tenantId); |
|
|
if (state != null) { |
|
|
if (state != null) { |
|
|
return state; |
|
|
return state; |
|
|
} else { |
|
|
} else { |
|
|
@ -213,11 +230,11 @@ public class DefaultTbApiUsageStateService extends TbApplicationEventListener<Pa |
|
|
} else { |
|
|
} else { |
|
|
updateLock.lock(); |
|
|
updateLock.lock(); |
|
|
try { |
|
|
try { |
|
|
state = otherTenantStates.get(tenantId); |
|
|
state = otherUsageStates.get(tenantId); |
|
|
if (state == null) { |
|
|
if (state == null) { |
|
|
state = apiUsageStateService.findTenantApiUsageState(tenantId); |
|
|
state = apiUsageStateService.findTenantApiUsageState(tenantId); |
|
|
if (state != null) { |
|
|
if (state != null) { |
|
|
otherTenantStates.put(tenantId, state); |
|
|
otherUsageStates.put(tenantId, state); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} finally { |
|
|
} finally { |
|
|
@ -231,7 +248,7 @@ public class DefaultTbApiUsageStateService extends TbApplicationEventListener<Pa |
|
|
|
|
|
|
|
|
@Override |
|
|
@Override |
|
|
public void onApiUsageStateUpdate(TenantId tenantId) { |
|
|
public void onApiUsageStateUpdate(TenantId tenantId) { |
|
|
otherTenantStates.remove(tenantId); |
|
|
otherUsageStates.remove(tenantId); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@Override |
|
|
@Override |
|
|
@ -240,11 +257,14 @@ public class DefaultTbApiUsageStateService extends TbApplicationEventListener<Pa |
|
|
TenantProfile tenantProfile = tenantProfileCache.get(tenantProfileId); |
|
|
TenantProfile tenantProfile = tenantProfileCache.get(tenantProfileId); |
|
|
updateLock.lock(); |
|
|
updateLock.lock(); |
|
|
try { |
|
|
try { |
|
|
myTenantStates.values().forEach(state -> { |
|
|
myUsageStates.values().stream() |
|
|
if (tenantProfile.getId().equals(state.getTenantProfileId())) { |
|
|
.filter(state -> state.getEntityType() == EntityType.TENANT) |
|
|
updateTenantState(state, tenantProfile); |
|
|
.map(state -> (TenantApiUsageState) state) |
|
|
} |
|
|
.forEach(state -> { |
|
|
}); |
|
|
if (tenantProfile.getId().equals(state.getTenantProfileId())) { |
|
|
|
|
|
updateTenantState(state, tenantProfile); |
|
|
|
|
|
} |
|
|
|
|
|
}); |
|
|
} finally { |
|
|
} finally { |
|
|
updateLock.unlock(); |
|
|
updateLock.unlock(); |
|
|
} |
|
|
} |
|
|
@ -256,7 +276,7 @@ public class DefaultTbApiUsageStateService extends TbApplicationEventListener<Pa |
|
|
TenantProfile tenantProfile = tenantProfileCache.get(tenantId); |
|
|
TenantProfile tenantProfile = tenantProfileCache.get(tenantId); |
|
|
updateLock.lock(); |
|
|
updateLock.lock(); |
|
|
try { |
|
|
try { |
|
|
TenantApiUsageState state = myTenantStates.get(tenantId); |
|
|
TenantApiUsageState state = (TenantApiUsageState) myUsageStates.get(tenantId); |
|
|
if (state != null && !state.getTenantProfileId().equals(tenantProfile.getId())) { |
|
|
if (state != null && !state.getTenantProfileId().equals(tenantProfile.getId())) { |
|
|
updateTenantState(state, tenantProfile); |
|
|
updateTenantState(state, tenantProfile); |
|
|
} |
|
|
} |
|
|
@ -293,8 +313,8 @@ public class DefaultTbApiUsageStateService extends TbApplicationEventListener<Pa |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
private void persistAndNotify(TenantApiUsageState state, Map<ApiFeature, ApiUsageStateValue> result) { |
|
|
private void persistAndNotify(BaseApiUsageState state, Map<ApiFeature, ApiUsageStateValue> result) { |
|
|
log.info("[{}] Detected update of the API state: {}", state.getTenantId(), result); |
|
|
log.info("[{}] Detected update of the API state for {}: {}", state.getEntityId(), state.getEntityType(), 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(); |
|
|
@ -302,20 +322,21 @@ public class DefaultTbApiUsageStateService extends TbApplicationEventListener<Pa |
|
|
result.forEach(((apiFeature, aState) -> stateTelemetry.add(new BasicTsKvEntry(ts, new StringDataEntry(apiFeature.getApiStateKey(), aState.name()))))); |
|
|
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); |
|
|
|
|
|
|
|
|
String email = tenantService.findTenantById(state.getTenantId()).getEmail(); |
|
|
if (state.getEntityType() == EntityType.TENANT) { |
|
|
|
|
|
String email = tenantService.findTenantById(state.getTenantId()).getEmail(); |
|
|
if (StringUtils.isNotEmpty(email)) { |
|
|
if (StringUtils.isNotEmpty(email)) { |
|
|
result.forEach((apiFeature, stateValue) -> { |
|
|
result.forEach((apiFeature, stateValue) -> { |
|
|
mailExecutor.submit(() -> { |
|
|
mailExecutor.submit(() -> { |
|
|
try { |
|
|
try { |
|
|
mailService.sendApiFeatureStateEmail(apiFeature, stateValue, email, createStateMailMessage(state, apiFeature, stateValue)); |
|
|
mailService.sendApiFeatureStateEmail(apiFeature, stateValue, email, createStateMailMessage((TenantApiUsageState) state, apiFeature, stateValue)); |
|
|
} catch (ThingsboardException e) { |
|
|
} catch (ThingsboardException e) { |
|
|
log.warn("[{}] Can't send update of the API state to tenant with provided email [{}]", state.getTenantId(), email, e); |
|
|
log.warn("[{}] Can't send update of the API state to tenant with provided email [{}]", state.getTenantId(), email, e); |
|
|
} |
|
|
} |
|
|
|
|
|
}); |
|
|
}); |
|
|
}); |
|
|
}); |
|
|
} else { |
|
|
} else { |
|
|
log.warn("[{}] Can't send update of the API state to tenant with empty email!", state.getTenantId()); |
|
|
log.warn("[{}] Can't send update of the API state to tenant with empty email!", state.getTenantId()); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@ -350,12 +371,13 @@ public class DefaultTbApiUsageStateService extends TbApplicationEventListener<Pa |
|
|
updateLock.lock(); |
|
|
updateLock.lock(); |
|
|
try { |
|
|
try { |
|
|
long now = System.currentTimeMillis(); |
|
|
long now = System.currentTimeMillis(); |
|
|
myTenantStates.values().forEach(state -> { |
|
|
myUsageStates.values().forEach(state -> { |
|
|
if ((state.getNextCycleTs() < now) && (now - state.getNextCycleTs() < TimeUnit.HOURS.toMillis(1))) { |
|
|
if ((state.getNextCycleTs() < now) && (now - state.getNextCycleTs() < TimeUnit.HOURS.toMillis(1))) { |
|
|
|
|
|
// FIXME
|
|
|
TenantId tenantId = state.getTenantId(); |
|
|
TenantId tenantId = state.getTenantId(); |
|
|
state.setCycles(state.getNextCycleTs(), SchedulerUtils.getStartOfNextNextMonth()); |
|
|
state.setCycles(state.getNextCycleTs(), SchedulerUtils.getStartOfNextNextMonth()); |
|
|
saveNewCounts(state, Arrays.asList(ApiUsageRecordKey.values())); |
|
|
saveNewCounts(state, Arrays.asList(ApiUsageRecordKey.values())); |
|
|
updateTenantState(state, tenantProfileCache.get(tenantId)); |
|
|
updateTenantState((TenantApiUsageState) state, tenantProfileCache.get(tenantId)); |
|
|
} |
|
|
} |
|
|
}); |
|
|
}); |
|
|
} finally { |
|
|
} finally { |
|
|
@ -363,7 +385,7 @@ public class DefaultTbApiUsageStateService extends TbApplicationEventListener<Pa |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
private void saveNewCounts(TenantApiUsageState state, List<ApiUsageRecordKey> keys) { |
|
|
private void saveNewCounts(BaseApiUsageState state, List<ApiUsageRecordKey> keys) { |
|
|
List<TsKvEntry> counts = keys.stream() |
|
|
List<TsKvEntry> counts = keys.stream() |
|
|
.map(key -> new BasicTsKvEntry(state.getCurrentCycleTs(), new LongDataEntry(key.getApiCountKey(), 0L))) |
|
|
.map(key -> new BasicTsKvEntry(state.getCurrentCycleTs(), new LongDataEntry(key.getApiCountKey(), 0L))) |
|
|
.collect(Collectors.toList()); |
|
|
.collect(Collectors.toList()); |
|
|
@ -371,13 +393,74 @@ public class DefaultTbApiUsageStateService extends TbApplicationEventListener<Pa |
|
|
tsWsService.saveAndNotifyInternal(state.getTenantId(), state.getApiUsageState().getId(), counts, VOID_CALLBACK); |
|
|
tsWsService.saveAndNotifyInternal(state.getTenantId(), state.getApiUsageState().getId(), counts, VOID_CALLBACK); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private BaseApiUsageState getOrFetchState(TenantId tenantId, EntityId entityId) { |
|
|
|
|
|
BaseApiUsageState state = myUsageStates.get(entityId); |
|
|
|
|
|
if (state != null) { |
|
|
|
|
|
return state; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
ApiUsageState storedState = Optional.ofNullable(apiUsageStateService.findApiUsageStateByEntityId(entityId)) |
|
|
|
|
|
.orElseGet(() -> { |
|
|
|
|
|
try { |
|
|
|
|
|
return apiUsageStateService.createDefaultApiUsageState(tenantId, entityId); |
|
|
|
|
|
} catch (Exception e) { |
|
|
|
|
|
return apiUsageStateService.findApiUsageStateByEntityId(entityId); |
|
|
|
|
|
} |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
switch (entityId.getEntityType()) { |
|
|
|
|
|
case TENANT: |
|
|
|
|
|
TenantProfile tenantProfile = tenantProfileCache.get(tenantId); |
|
|
|
|
|
state = new TenantApiUsageState(tenantProfile, storedState); |
|
|
|
|
|
break; |
|
|
|
|
|
case CUSTOMER: |
|
|
|
|
|
default: |
|
|
|
|
|
state = new CustomerApiUsageState(storedState); |
|
|
|
|
|
break; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
List<ApiUsageRecordKey> newCounts = new ArrayList<>(); |
|
|
|
|
|
try { |
|
|
|
|
|
List<TsKvEntry> dbValues = tsService.findAllLatest(tenantId, storedState.getId()).get(); |
|
|
|
|
|
for (ApiUsageRecordKey key : ApiUsageRecordKey.values()) { |
|
|
|
|
|
boolean cycleEntryFound = false; |
|
|
|
|
|
boolean hourlyEntryFound = false; |
|
|
|
|
|
for (TsKvEntry tsKvEntry : dbValues) { |
|
|
|
|
|
if (tsKvEntry.getKey().equals(key.getApiCountKey())) { |
|
|
|
|
|
cycleEntryFound = true; |
|
|
|
|
|
|
|
|
|
|
|
boolean oldCount = tsKvEntry.getTs() == state.getCurrentCycleTs(); |
|
|
|
|
|
state.put(key, oldCount ? tsKvEntry.getLongValue().get() : 0L); |
|
|
|
|
|
|
|
|
|
|
|
if (!oldCount) { |
|
|
|
|
|
newCounts.add(key); |
|
|
|
|
|
} |
|
|
|
|
|
} else if (tsKvEntry.getKey().equals(key.getApiCountKey() + HOURLY)) { |
|
|
|
|
|
hourlyEntryFound = true; |
|
|
|
|
|
state.putHourly(key, tsKvEntry.getTs() == state.getCurrentHourTs() ? tsKvEntry.getLongValue().get() : 0L); |
|
|
|
|
|
} |
|
|
|
|
|
if (cycleEntryFound && hourlyEntryFound) { |
|
|
|
|
|
break; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
log.debug("[{}] Initialized state: {}", entityId, storedState); |
|
|
|
|
|
myUsageStates.put(entityId, state); |
|
|
|
|
|
saveNewCounts(state, newCounts); |
|
|
|
|
|
} catch (InterruptedException | ExecutionException e) { |
|
|
|
|
|
log.warn("[{}] Failed to fetch api usage state from db.", tenantId, e); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return state; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
private TenantApiUsageState getOrFetchState(TenantId tenantId) { |
|
|
private TenantApiUsageState getOrFetchState(TenantId tenantId) { |
|
|
TenantApiUsageState tenantState = myTenantStates.get(tenantId); |
|
|
TenantApiUsageState tenantState = (TenantApiUsageState) myUsageStates.get(tenantId); |
|
|
if (tenantState == null) { |
|
|
if (tenantState == null) { |
|
|
ApiUsageState dbStateEntity = apiUsageStateService.findTenantApiUsageState(tenantId); |
|
|
ApiUsageState dbStateEntity = apiUsageStateService.findTenantApiUsageState(tenantId); |
|
|
if (dbStateEntity == null) { |
|
|
if (dbStateEntity == null) { |
|
|
try { |
|
|
try { |
|
|
dbStateEntity = apiUsageStateService.createDefaultApiUsageState(tenantId); |
|
|
dbStateEntity = apiUsageStateService.createDefaultApiUsageState(tenantId, null); |
|
|
} catch (Exception e) { |
|
|
} catch (Exception e) { |
|
|
dbStateEntity = apiUsageStateService.findTenantApiUsageState(tenantId); |
|
|
dbStateEntity = apiUsageStateService.findTenantApiUsageState(tenantId); |
|
|
} |
|
|
} |
|
|
@ -410,7 +493,7 @@ public class DefaultTbApiUsageStateService extends TbApplicationEventListener<Pa |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
log.debug("[{}] Initialized state: {}", tenantId, dbStateEntity); |
|
|
log.debug("[{}] Initialized state: {}", tenantId, dbStateEntity); |
|
|
myTenantStates.put(tenantId, tenantState); |
|
|
myUsageStates.put(tenantId, tenantState); |
|
|
saveNewCounts(tenantState, newCounts); |
|
|
saveNewCounts(tenantState, newCounts); |
|
|
} catch (InterruptedException | ExecutionException e) { |
|
|
} catch (InterruptedException | ExecutionException e) { |
|
|
log.warn("[{}] Failed to fetch api usage state from db.", tenantId, e); |
|
|
log.warn("[{}] Failed to fetch api usage state from db.", tenantId, e); |
|
|
@ -429,7 +512,7 @@ public class DefaultTbApiUsageStateService extends TbApplicationEventListener<Pa |
|
|
PageDataIterable<Tenant> tenantIterator = new PageDataIterable<>(tenantService::findTenants, 1024); |
|
|
PageDataIterable<Tenant> tenantIterator = new PageDataIterable<>(tenantService::findTenants, 1024); |
|
|
List<Future<?>> futures = new ArrayList<>(); |
|
|
List<Future<?>> futures = new ArrayList<>(); |
|
|
for (Tenant tenant : tenantIterator) { |
|
|
for (Tenant tenant : tenantIterator) { |
|
|
if (!myTenantStates.containsKey(tenant.getId()) && partitionService.resolve(ServiceType.TB_CORE, tenant.getId(), tenant.getId()).isMyPartition()) { |
|
|
if (!myUsageStates.containsKey(tenant.getId()) && partitionService.resolve(ServiceType.TB_CORE, tenant.getId(), tenant.getId()).isMyPartition()) { |
|
|
log.debug("[{}] Initializing tenant state.", tenant.getId()); |
|
|
log.debug("[{}] Initializing tenant state.", tenant.getId()); |
|
|
futures.add(tmpInitExecutor.submit(() -> { |
|
|
futures.add(tmpInitExecutor.submit(() -> { |
|
|
try { |
|
|
try { |
|
|
|