fix prod runtime logging and room discovery
This commit is contained in:
parent
096e37612e
commit
e2e59eb1b2
@ -2,8 +2,3 @@ spring:
|
|||||||
data:
|
data:
|
||||||
mongodb:
|
mongodb:
|
||||||
uri: ${LIKEI_MONGO_URI}
|
uri: ${LIKEI_MONGO_URI}
|
||||||
|
|
||||||
|
|
||||||
logging:
|
|
||||||
level:
|
|
||||||
org.springframework.data.mongodb.core.MongoTemplate: DEBUG
|
|
||||||
|
|||||||
@ -20,7 +20,6 @@ import org.springframework.core.Ordered;
|
|||||||
import org.springframework.core.io.buffer.DataBuffer;
|
import org.springframework.core.io.buffer.DataBuffer;
|
||||||
import org.springframework.core.io.buffer.DataBufferFactory;
|
import org.springframework.core.io.buffer.DataBufferFactory;
|
||||||
import org.springframework.core.io.buffer.DataBufferUtils;
|
import org.springframework.core.io.buffer.DataBufferUtils;
|
||||||
import org.springframework.core.io.buffer.DefaultDataBufferFactory;
|
|
||||||
import org.springframework.http.HttpHeaders;
|
import org.springframework.http.HttpHeaders;
|
||||||
import org.springframework.http.HttpStatusCode;
|
import org.springframework.http.HttpStatusCode;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
@ -39,6 +38,7 @@ import org.springframework.web.server.ServerWebExchange;
|
|||||||
import reactor.core.publisher.Flux;
|
import reactor.core.publisher.Flux;
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
@ -57,6 +57,8 @@ import java.util.zip.GZIPInputStream;
|
|||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class ApiLoggingFilter implements GlobalFilter, Ordered {
|
public class ApiLoggingFilter implements GlobalFilter, Ordered {
|
||||||
|
|
||||||
|
private static final int MAX_RESPONSE_BODY_LOG_LENGTH = 500;
|
||||||
|
|
||||||
private final LoggingUploadService loggingUploadService;
|
private final LoggingUploadService loggingUploadService;
|
||||||
private final List<HttpMessageReader<?>> messageReaders = HandlerStrategies.withDefaults()
|
private final List<HttpMessageReader<?>> messageReaders = HandlerStrategies.withDefaults()
|
||||||
.messageReaders();
|
.messageReaders();
|
||||||
@ -164,40 +166,17 @@ public class ApiLoggingFilter implements GlobalFilter, Ordered {
|
|||||||
.map(HttpStatusCode::value)
|
.map(HttpStatusCode::value)
|
||||||
.map(Objects::toString)
|
.map(Objects::toString)
|
||||||
.orElse("?"));
|
.orElse("?"));
|
||||||
if (body instanceof Flux) {
|
if (body instanceof Flux && !isSuccessResponse(response)) {
|
||||||
// 获取响应类型,如果是 json 就打印
|
// 获取响应类型,如果是 json 就打印
|
||||||
String originalResponseContentType = exchange.getAttribute(ServerWebExchangeUtils.ORIGINAL_RESPONSE_CONTENT_TYPE_ATTR);
|
if (isJsonResponse(exchange, response)) {
|
||||||
|
return super.writeWith(DataBufferUtils.join(Flux.from(body)).map(dataBuffer -> {
|
||||||
|
byte[] content = new byte[dataBuffer.readableByteCount()];
|
||||||
|
dataBuffer.read(content);
|
||||||
|
DataBufferUtils.release(dataBuffer);
|
||||||
|
|
||||||
if (StringUtils.isNotBlank(originalResponseContentType) && originalResponseContentType.contains("application/json")) {
|
String responseResult = readResponseBody(exchange, content);
|
||||||
|
responseResult = responseResult.substring(0, Math.min(responseResult.length(), MAX_RESPONSE_BODY_LOG_LENGTH));
|
||||||
Flux<? extends DataBuffer> fluxBody = Flux.from(body);
|
|
||||||
return super.writeWith(fluxBody.buffer().map(dataBuffers -> {
|
|
||||||
|
|
||||||
// 合并多个流集合,解决返回体分段传输
|
|
||||||
DataBufferFactory dataBufferFactory = new DefaultDataBufferFactory();
|
|
||||||
DataBuffer join = dataBufferFactory.join(dataBuffers);
|
|
||||||
byte[] content = new byte[join.readableByteCount()];
|
|
||||||
join.read(content);
|
|
||||||
|
|
||||||
// 释放掉内存
|
|
||||||
DataBufferUtils.release(join);
|
|
||||||
|
|
||||||
try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
|
|
||||||
try (GZIPInputStream in = new GZIPInputStream(new java.io.ByteArrayInputStream(content))) {
|
|
||||||
byte[] buffer = new byte[1024];
|
|
||||||
int len;
|
|
||||||
while ((len = in.read(buffer)) > 0) {
|
|
||||||
out.write(buffer, 0, len);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
String responseResult = out.toString(StandardCharsets.UTF_8);
|
|
||||||
// 截取500个字符
|
|
||||||
responseResult = responseResult.substring(0, Math.min(responseResult.length(), 500));
|
|
||||||
loggingResponse.setBody(responseResult);
|
loggingResponse.setBody(responseResult);
|
||||||
} catch (IOException e) {
|
|
||||||
log.error("Failed to decompress data", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
return bufferFactory.wrap(content);
|
return bufferFactory.wrap(content);
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
@ -207,6 +186,52 @@ public class ApiLoggingFilter implements GlobalFilter, Ordered {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isSuccessResponse(ServerHttpResponse response) {
|
||||||
|
HttpStatusCode statusCode = response.getStatusCode();
|
||||||
|
return statusCode == null || statusCode.is2xxSuccessful();
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isJsonResponse(ServerWebExchange exchange, ServerHttpResponse response) {
|
||||||
|
String originalResponseContentType = exchange.getAttribute(ServerWebExchangeUtils.ORIGINAL_RESPONSE_CONTENT_TYPE_ATTR);
|
||||||
|
if (StringUtils.isNotBlank(originalResponseContentType) && originalResponseContentType.contains(MediaType.APPLICATION_JSON_VALUE)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
MediaType contentType = response.getHeaders().getContentType();
|
||||||
|
return contentType != null && MediaType.APPLICATION_JSON.isCompatibleWith(contentType);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String readResponseBody(ServerWebExchange exchange, byte[] content) {
|
||||||
|
if (!isGzipResponse(exchange, content)) {
|
||||||
|
return new String(content, StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
try (ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
|
GZIPInputStream in = new GZIPInputStream(new ByteArrayInputStream(content))) {
|
||||||
|
byte[] buffer = new byte[1024];
|
||||||
|
int len;
|
||||||
|
while ((len = in.read(buffer)) > 0) {
|
||||||
|
out.write(buffer, 0, len);
|
||||||
|
}
|
||||||
|
return out.toString(StandardCharsets.UTF_8);
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.warn("Failed to read gzip response body for logging: {}", e.getMessage());
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isGzipResponse(ServerWebExchange exchange, byte[] content) {
|
||||||
|
boolean gzipHeader = exchange.getResponse().getHeaders().getOrEmpty(HttpHeaders.CONTENT_ENCODING)
|
||||||
|
.stream()
|
||||||
|
.anyMatch(value -> StringUtils.isNotBlank(value) && value.toLowerCase().contains("gzip"));
|
||||||
|
return gzipHeader || hasGzipMagic(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasGzipMagic(byte[] content) {
|
||||||
|
return content != null
|
||||||
|
&& content.length >= 2
|
||||||
|
&& (content[0] & 0xff) == 0x1f
|
||||||
|
&& (content[1] & 0xff) == 0x8b;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 请求装饰器,重新计算 headers.
|
* 请求装饰器,重新计算 headers.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -24,7 +24,7 @@ public class LoggingUploadService {
|
|||||||
private String getTopic() {
|
private String getTopic() {
|
||||||
log.info("profileActive: {}", profileActive);
|
log.info("profileActive: {}", profileActive);
|
||||||
if (Objects.equals(profileActive, "prod")) {
|
if (Objects.equals(profileActive, "prod")) {
|
||||||
return "4d467d31-9165-42c6-b80a-2ea23ae7777e";
|
return "4fd8ef93-1c0c-4802-a999-9268831a3ee5";
|
||||||
}
|
}
|
||||||
|
|
||||||
// if (Objects.equals(profileActive, "dev")) {
|
// if (Objects.equals(profileActive, "dev")) {
|
||||||
|
|||||||
@ -2,7 +2,6 @@ package com.red.circle.other.app.command.room.query;
|
|||||||
|
|
||||||
import com.alibaba.fastjson.JSON;
|
import com.alibaba.fastjson.JSON;
|
||||||
import com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
import com.google.gson.Gson;
|
|
||||||
import com.red.circle.common.business.dto.cmd.AppExtCommand;
|
import com.red.circle.common.business.dto.cmd.AppExtCommand;
|
||||||
import com.red.circle.common.business.enums.SVIPLevelEnum;
|
import com.red.circle.common.business.enums.SVIPLevelEnum;
|
||||||
import com.red.circle.live.inner.endpoint.LiveMicClient;
|
import com.red.circle.live.inner.endpoint.LiveMicClient;
|
||||||
@ -31,15 +30,13 @@ import com.red.circle.other.infra.database.rds.service.user.device.LatestMobileD
|
|||||||
import com.red.circle.other.inner.model.cmd.live.AppActiveVoiceRoomQryCmd;
|
import com.red.circle.other.inner.model.cmd.live.AppActiveVoiceRoomQryCmd;
|
||||||
import com.red.circle.other.inner.model.dto.live.ActiveVoiceRoomCO;
|
import com.red.circle.other.inner.model.dto.live.ActiveVoiceRoomCO;
|
||||||
import com.red.circle.tool.core.collection.CollectionUtils;
|
import com.red.circle.tool.core.collection.CollectionUtils;
|
||||||
import com.google.gson.reflect.TypeToken;
|
|
||||||
import java.lang.reflect.Type;
|
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.function.Function;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.beans.BeanUtils;
|
import org.springframework.beans.BeanUtils;
|
||||||
|
import org.springframework.data.redis.core.ScanOptions;
|
||||||
import org.springframework.data.redis.core.RedisTemplate;
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
@ -72,18 +69,29 @@ public class RoomVoiceDiscoverQryExe {
|
|||||||
private static final String EMPTY_ROOM_CACHE_KEY = "empty_room_cache:*";
|
private static final String EMPTY_ROOM_CACHE_KEY = "empty_room_cache:*";
|
||||||
private static final String MEMBER_QUANTITY_EXT_KEY = "memberQuantity";
|
private static final String MEMBER_QUANTITY_EXT_KEY = "memberQuantity";
|
||||||
private static final int DISCOVERY_LIMIT = 50;
|
private static final int DISCOVERY_LIMIT = 50;
|
||||||
|
private static final long DISCOVERY_SLOW_STEP_MILLIS = 100L;
|
||||||
|
private static final long DISCOVERY_SLOW_TOTAL_MILLIS = 300L;
|
||||||
|
private static final long EMPTY_ROOM_SCAN_COUNT = 200L;
|
||||||
|
|
||||||
public List<RoomVoiceProfileCO> execute(AppExtCommand cmd) {
|
public List<RoomVoiceProfileCO> execute(AppExtCommand cmd) {
|
||||||
boolean allRegionWhiteListUser = roomRegionFilterCommon.canViewAllRegions(cmd.requiredReqUserId());
|
long totalStart = System.currentTimeMillis();
|
||||||
RegionConfig currentRegion = roomRegionFilterCommon.requireRegionConfig(cmd.requiredReqUserId());
|
long stepStart = totalStart;
|
||||||
String region = currentRegion.getRegionCode();
|
Long reqUserId = cmd.requiredReqUserId();
|
||||||
UserProfile userProfile = userProfileGateway.getByUserId(cmd.requiredReqUserId());
|
String sysOrigin = cmd.requireReqSysOrigin();
|
||||||
|
|
||||||
String key = discoveryCacheKey(cmd.requireReqSysOrigin(), region, allRegionWhiteListUser);
|
boolean allRegionWhiteListUser = roomRegionFilterCommon.canViewAllRegions(reqUserId);
|
||||||
|
RegionConfig currentRegion = roomRegionFilterCommon.requireRegionConfig(reqUserId);
|
||||||
|
String region = currentRegion.getRegionCode();
|
||||||
|
UserProfile userProfile = userProfileGateway.getByUserId(reqUserId);
|
||||||
|
stepStart = logDiscoveryStep("prepare", stepStart, reqUserId, sysOrigin, region);
|
||||||
|
|
||||||
|
String key = discoveryCacheKey(sysOrigin, region, allRegionWhiteListUser);
|
||||||
String regionsRoom = regionRoomCacheService.getRegionsRoom(key);
|
String regionsRoom = regionRoomCacheService.getRegionsRoom(key);
|
||||||
|
stepStart = logDiscoveryStep("read-region-cache", stepStart, reqUserId, sysOrigin, region);
|
||||||
if (Objects.nonNull(regionsRoom)) {
|
if (Objects.nonNull(regionsRoom)) {
|
||||||
List<RoomVoiceProfileCO> roomList = JSON.parseArray(regionsRoom, RoomVoiceProfileCO.class);
|
List<RoomVoiceProfileCO> roomList = JSON.parseArray(regionsRoom, RoomVoiceProfileCO.class);
|
||||||
if (CollectionUtils.isEmpty(roomList)) {
|
if (CollectionUtils.isEmpty(roomList)) {
|
||||||
|
logDiscoveryTotal(totalStart, reqUserId, sysOrigin, region, allRegionWhiteListUser, true, 0);
|
||||||
return CollectionUtils.newArrayList();
|
return CollectionUtils.newArrayList();
|
||||||
}
|
}
|
||||||
List<RoomVoiceProfileCO> availableRooms = roomVoiceProfileCommon
|
List<RoomVoiceProfileCO> availableRooms = roomVoiceProfileCommon
|
||||||
@ -91,32 +99,36 @@ public class RoomVoiceDiscoverQryExe {
|
|||||||
if (availableRooms.size() != roomList.size()) {
|
if (availableRooms.size() != roomList.size()) {
|
||||||
regionRoomCacheService.remove(key);
|
regionRoomCacheService.remove(key);
|
||||||
}
|
}
|
||||||
|
stepStart = logDiscoveryStep("filter-cache", stepStart, reqUserId, sysOrigin, region);
|
||||||
|
logDiscoveryTotal(totalStart, reqUserId, sysOrigin, region, allRegionWhiteListUser, true, availableRooms.size());
|
||||||
return availableRooms;
|
return availableRooms;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<ActiveVoiceRoom> activeVoiceRooms = allRegionWhiteListUser
|
List<ActiveVoiceRoom> activeVoiceRooms = allRegionWhiteListUser
|
||||||
? activeVoiceRoomService.listDiscover(
|
? activeVoiceRoomService.listDiscover(
|
||||||
cmd.requireReqSysOrigin(),
|
sysOrigin,
|
||||||
true,
|
true,
|
||||||
region,
|
region,
|
||||||
Optional.ofNullable(userProfile).map(UserProfile::getCountryCode).orElse(null),
|
Optional.ofNullable(userProfile).map(UserProfile::getCountryCode).orElse(null),
|
||||||
DISCOVERY_LIMIT
|
DISCOVERY_LIMIT
|
||||||
)
|
)
|
||||||
: roomRegionFilterCommon.filterActiveVoiceRoomsByRegion(
|
: roomRegionFilterCommon.filterActiveVoiceRoomsByRegion(
|
||||||
activeVoiceRoomService.listByRegion(cmd.requireReqSysOrigin(), region, DISCOVERY_LIMIT),
|
activeVoiceRoomService.listByRegion(sysOrigin, region, DISCOVERY_LIMIT),
|
||||||
region
|
region
|
||||||
);
|
);
|
||||||
|
stepStart = logDiscoveryStep("query-active-rooms", stepStart, reqUserId, sysOrigin, region);
|
||||||
|
|
||||||
// 查询没人的房间缓存,加入进去
|
// 查询没人的房间缓存,加入进去
|
||||||
List<ActiveVoiceRoom> emptyRooms = getEmptyRoomsFromCache();
|
List<ActiveVoiceRoom> emptyRooms = getEmptyRoomsFromCache();
|
||||||
|
stepStart = logDiscoveryStep("scan-empty-room-cache", stepStart, reqUserId, sysOrigin, region);
|
||||||
if (CollectionUtils.isNotEmpty(emptyRooms)) {
|
if (CollectionUtils.isNotEmpty(emptyRooms)) {
|
||||||
List<ActiveVoiceRoom> matchedEmptyRooms = allRegionWhiteListUser
|
List<ActiveVoiceRoom> matchedEmptyRooms = allRegionWhiteListUser
|
||||||
? emptyRooms.stream()
|
? emptyRooms.stream()
|
||||||
.filter(room -> Objects.equals(cmd.requireReqSysOrigin(), room.getSysOrigin()))
|
.filter(room -> Objects.equals(sysOrigin, room.getSysOrigin()))
|
||||||
.toList()
|
.toList()
|
||||||
: roomRegionFilterCommon.filterActiveVoiceRoomsByRegion(
|
: roomRegionFilterCommon.filterActiveVoiceRoomsByRegion(
|
||||||
emptyRooms.stream()
|
emptyRooms.stream()
|
||||||
.filter(room -> Objects.equals(cmd.requireReqSysOrigin(), room.getSysOrigin()))
|
.filter(room -> Objects.equals(sysOrigin, room.getSysOrigin()))
|
||||||
.toList(),
|
.toList(),
|
||||||
region
|
region
|
||||||
);
|
);
|
||||||
@ -131,10 +143,13 @@ public class RoomVoiceDiscoverQryExe {
|
|||||||
activeVoiceRooms = allRooms;
|
activeVoiceRooms = allRooms;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
stepStart = logDiscoveryStep("merge-empty-rooms", stepStart, reqUserId, sysOrigin, region);
|
||||||
|
|
||||||
List<RoomVoiceProfileCO> roomList = roomVoiceProfileCommon.toListRoomVoiceProfileCO(activeVoiceRooms);
|
List<RoomVoiceProfileCO> roomList = roomVoiceProfileCommon.toListRoomVoiceProfileCO(activeVoiceRooms);
|
||||||
|
stepStart = logDiscoveryStep("build-profile-list", stepStart, reqUserId, sysOrigin, region);
|
||||||
if (roomList.size() < DISCOVERY_LIMIT) {
|
if (roomList.size() < DISCOVERY_LIMIT) {
|
||||||
List<RoomProfileManager> fallbackRoomManagersSource = roomProfileManagerService.listSelectiveLimitByCountryCodes(
|
List<RoomProfileManager> fallbackRoomManagersSource = roomProfileManagerService.listSelectiveLimitByCountryCodes(
|
||||||
cmd.requireReqSysOrigin(),
|
sysOrigin,
|
||||||
allRegionWhiteListUser ? List.of() : roomRegionFilterCommon.listCountryCodes(currentRegion),
|
allRegionWhiteListUser ? List.of() : roomRegionFilterCommon.listCountryCodes(currentRegion),
|
||||||
roomList.stream().map(RoomVoiceProfileCO::getId).toList(),
|
roomList.stream().map(RoomVoiceProfileCO::getId).toList(),
|
||||||
DISCOVERY_LIMIT
|
DISCOVERY_LIMIT
|
||||||
@ -148,9 +163,12 @@ public class RoomVoiceDiscoverQryExe {
|
|||||||
roomList = mergeRoomList(roomList, roomVoiceProfileCommon.listRoomVoiceProfilesV2(fallbackRoomManagers),
|
roomList = mergeRoomList(roomList, roomVoiceProfileCommon.listRoomVoiceProfilesV2(fallbackRoomManagers),
|
||||||
DISCOVERY_LIMIT);
|
DISCOVERY_LIMIT);
|
||||||
}
|
}
|
||||||
|
stepStart = logDiscoveryStep("fallback-room-profiles", stepStart, reqUserId, sysOrigin, region);
|
||||||
roomList = sortByMemberQuantityDesc(roomList);
|
roomList = sortByMemberQuantityDesc(roomList);
|
||||||
|
stepStart = logDiscoveryStep("sort-rooms", stepStart, reqUserId, sysOrigin, region);
|
||||||
|
|
||||||
if (CollectionUtils.isEmpty(roomList)) {
|
if (CollectionUtils.isEmpty(roomList)) {
|
||||||
|
logDiscoveryTotal(totalStart, reqUserId, sysOrigin, region, allRegionWhiteListUser, false, 0);
|
||||||
return CollectionUtils.newArrayList();
|
return CollectionUtils.newArrayList();
|
||||||
}
|
}
|
||||||
Map<Long, SVIPLevelEnum> svipLevelEnumMap = userSVipGateway.checkSVipIdentity(
|
Map<Long, SVIPLevelEnum> svipLevelEnumMap = userSVipGateway.checkSVipIdentity(
|
||||||
@ -161,11 +179,17 @@ public class RoomVoiceDiscoverQryExe {
|
|||||||
room.setUserSVipLevel(svipLevelEnumMap.get(room.getUserId()));
|
room.setUserSVipLevel(svipLevelEnumMap.get(room.getUserId()));
|
||||||
})
|
})
|
||||||
.toList();
|
.toList();
|
||||||
|
stepStart = logDiscoveryStep("fill-svip", stepStart, reqUserId, sysOrigin, region);
|
||||||
|
|
||||||
// 填充火箭状态
|
// 填充火箭状态
|
||||||
fillRocketStatus(roomList);
|
fillRocketStatus(roomList);
|
||||||
|
stepStart = logDiscoveryStep("fill-rocket-status", stepStart, reqUserId, sysOrigin, region);
|
||||||
// 填充游戏图标
|
// 填充游戏图标
|
||||||
fillGameIcon(roomList);
|
fillGameIcon(roomList);
|
||||||
|
stepStart = logDiscoveryStep("fill-game-icon", stepStart, reqUserId, sysOrigin, region);
|
||||||
|
saveDiscoveryCache(key, roomList, reqUserId, sysOrigin, region);
|
||||||
|
logDiscoveryStep("write-region-cache", stepStart, reqUserId, sysOrigin, region);
|
||||||
|
logDiscoveryTotal(totalStart, reqUserId, sysOrigin, region, allRegionWhiteListUser, false, roomList.size());
|
||||||
|
|
||||||
return roomList;
|
return roomList;
|
||||||
}
|
}
|
||||||
@ -201,6 +225,38 @@ public class RoomVoiceDiscoverQryExe {
|
|||||||
return allRegionWhiteListUser ? sysOrigin + region + ":ALL_REGION" : sysOrigin + region;
|
return allRegionWhiteListUser ? sysOrigin + region + ":ALL_REGION" : sysOrigin + region;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void saveDiscoveryCache(String key, List<RoomVoiceProfileCO> roomList, Long userId,
|
||||||
|
String sysOrigin, String region) {
|
||||||
|
if (CollectionUtils.isEmpty(roomList)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
regionRoomCacheService.saveRegionsRoom(JSON.toJSONString(roomList), key);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("写入房间发现缓存失败, key={}, userId={}, sysOrigin={}, region={}",
|
||||||
|
key, userId, sysOrigin, region, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private long logDiscoveryStep(String step, long stepStart, Long userId, String sysOrigin, String region) {
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
|
long cost = now - stepStart;
|
||||||
|
if (cost >= DISCOVERY_SLOW_STEP_MILLIS) {
|
||||||
|
log.warn("房间发现慢步骤, step={}, cost={}ms, userId={}, sysOrigin={}, region={}",
|
||||||
|
step, cost, userId, sysOrigin, region);
|
||||||
|
}
|
||||||
|
return now;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void logDiscoveryTotal(long totalStart, Long userId, String sysOrigin, String region,
|
||||||
|
boolean allRegionWhiteListUser, boolean cacheHit, int roomCount) {
|
||||||
|
long cost = System.currentTimeMillis() - totalStart;
|
||||||
|
if (cost >= DISCOVERY_SLOW_TOTAL_MILLIS) {
|
||||||
|
log.warn("房间发现总耗时慢, cost={}ms, userId={}, sysOrigin={}, region={}, allRegion={}, cacheHit={}, roomCount={}",
|
||||||
|
cost, userId, sysOrigin, region, allRegionWhiteListUser, cacheHit, roomCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private List<RoomVoiceProfileCO> mergeRoomList(List<RoomVoiceProfileCO> currentRooms,
|
private List<RoomVoiceProfileCO> mergeRoomList(List<RoomVoiceProfileCO> currentRooms,
|
||||||
List<RoomVoiceProfileCO> fallbackRooms, int limit) {
|
List<RoomVoiceProfileCO> fallbackRooms, int limit) {
|
||||||
if (CollectionUtils.isEmpty(fallbackRooms)) {
|
if (CollectionUtils.isEmpty(fallbackRooms)) {
|
||||||
@ -350,7 +406,7 @@ public class RoomVoiceDiscoverQryExe {
|
|||||||
*/
|
*/
|
||||||
private List<ActiveVoiceRoom> getEmptyRoomsFromCache() {
|
private List<ActiveVoiceRoom> getEmptyRoomsFromCache() {
|
||||||
try {
|
try {
|
||||||
Set<String> keys = redisTemplate.keys(EMPTY_ROOM_CACHE_KEY);
|
Set<String> keys = scanEmptyRoomKeys();
|
||||||
if (CollectionUtils.isEmpty(keys)) {
|
if (CollectionUtils.isEmpty(keys)) {
|
||||||
return new ArrayList<>();
|
return new ArrayList<>();
|
||||||
}
|
}
|
||||||
@ -380,6 +436,23 @@ public class RoomVoiceDiscoverQryExe {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Set<String> scanEmptyRoomKeys() {
|
||||||
|
Set<String> keys = new HashSet<>();
|
||||||
|
ScanOptions options = ScanOptions.scanOptions()
|
||||||
|
.match(EMPTY_ROOM_CACHE_KEY)
|
||||||
|
.count(EMPTY_ROOM_SCAN_COUNT)
|
||||||
|
.build();
|
||||||
|
try (var cursor = redisTemplate.scan(options)) {
|
||||||
|
if (Objects.isNull(cursor)) {
|
||||||
|
return keys;
|
||||||
|
}
|
||||||
|
while (cursor.hasNext()) {
|
||||||
|
keys.add(Objects.toString(cursor.next(), ""));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return keys;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 将ActiveVoiceRoomCO转换为ActiveVoiceRoom
|
* 将ActiveVoiceRoomCO转换为ActiveVoiceRoom
|
||||||
*
|
*
|
||||||
|
|||||||
@ -47,6 +47,8 @@ public class RocketEnergyAggregator {
|
|||||||
private final StringRedisTemplate redisTemplate;
|
private final StringRedisTemplate redisTemplate;
|
||||||
@Value("${spring.profiles.active}")
|
@Value("${spring.profiles.active}")
|
||||||
private String activeProfile;
|
private String activeProfile;
|
||||||
|
@Value("${rocket.energy.enabled:false}")
|
||||||
|
private boolean rocketEnergyEnabled;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Redis 队列 Key 前缀
|
* Redis 队列 Key 前缀
|
||||||
@ -96,6 +98,9 @@ public class RocketEnergyAggregator {
|
|||||||
* 接收能量增加请求(写入Redis队列)
|
* 接收能量增加请求(写入Redis队列)
|
||||||
*/
|
*/
|
||||||
public void addEnergy(RocketEnergyAddCmd cmd) {
|
public void addEnergy(RocketEnergyAddCmd cmd) {
|
||||||
|
if (!rocketEnergyEnabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
Long roomId = cmd.getRoomId();
|
Long roomId = cmd.getRoomId();
|
||||||
String queueKey = getKey(String.valueOf(roomId)) ;
|
String queueKey = getKey(String.valueOf(roomId)) ;
|
||||||
@ -124,6 +129,9 @@ public class RocketEnergyAggregator {
|
|||||||
*/
|
*/
|
||||||
@Scheduled(fixedDelay = FLUSH_INTERVAL)
|
@Scheduled(fixedDelay = FLUSH_INTERVAL)
|
||||||
public void flushToDatabase() {
|
public void flushToDatabase() {
|
||||||
|
if (!rocketEnergyEnabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
// 获取所有活跃房间
|
// 获取所有活跃房间
|
||||||
Set<String> activeRooms = redisTemplate.opsForSet().members(getActiveRoomsKey());
|
Set<String> activeRooms = redisTemplate.opsForSet().members(getActiveRoomsKey());
|
||||||
@ -355,6 +363,9 @@ public class RocketEnergyAggregator {
|
|||||||
*/
|
*/
|
||||||
@Scheduled(fixedRate = 3600000)
|
@Scheduled(fixedRate = 3600000)
|
||||||
public void cleanupExpiredData() {
|
public void cleanupExpiredData() {
|
||||||
|
if (!rocketEnergyEnabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
// 清理本地推送时间缓存
|
// 清理本地推送时间缓存
|
||||||
Set<String> activeRooms = redisTemplate.opsForSet().members(getActiveRoomsKey());
|
Set<String> activeRooms = redisTemplate.opsForSet().members(getActiveRoomsKey());
|
||||||
@ -382,6 +393,9 @@ public class RocketEnergyAggregator {
|
|||||||
*/
|
*/
|
||||||
@javax.annotation.PreDestroy
|
@javax.annotation.PreDestroy
|
||||||
public void shutdown() {
|
public void shutdown() {
|
||||||
|
if (!rocketEnergyEnabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
log.info("应用关闭,强制刷新所有待处理能量");
|
log.info("应用关闭,强制刷新所有待处理能量");
|
||||||
try {
|
try {
|
||||||
flushToDatabase();
|
flushToDatabase();
|
||||||
@ -394,6 +408,10 @@ public class RocketEnergyAggregator {
|
|||||||
* 手动触发刷新(供运维使用)
|
* 手动触发刷新(供运维使用)
|
||||||
*/
|
*/
|
||||||
public void manualFlush() {
|
public void manualFlush() {
|
||||||
|
if (!rocketEnergyEnabled) {
|
||||||
|
log.info("火箭能量聚合未启用,跳过手动刷新");
|
||||||
|
return;
|
||||||
|
}
|
||||||
log.info("手动触发刷新");
|
log.info("手动触发刷新");
|
||||||
flushToDatabase();
|
flushToDatabase();
|
||||||
}
|
}
|
||||||
@ -403,6 +421,10 @@ public class RocketEnergyAggregator {
|
|||||||
*/
|
*/
|
||||||
public Map<String, Object> getQueueStatus() {
|
public Map<String, Object> getQueueStatus() {
|
||||||
Map<String, Object> status = new HashMap<>();
|
Map<String, Object> status = new HashMap<>();
|
||||||
|
status.put("enabled", rocketEnergyEnabled);
|
||||||
|
if (!rocketEnergyEnabled) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
Set<String> activeRooms = redisTemplate.opsForSet().members(getActiveRoomsKey());
|
Set<String> activeRooms = redisTemplate.opsForSet().members(getActiveRoomsKey());
|
||||||
status.put("activeRoomCount", activeRooms != null ? activeRooms.size() : 0);
|
status.put("activeRoomCount", activeRooms != null ? activeRooms.size() : 0);
|
||||||
|
|||||||
@ -8,7 +8,7 @@ public enum LogTopic {
|
|||||||
/**
|
/**
|
||||||
* 钱包金币资产.
|
* 钱包金币资产.
|
||||||
*/
|
*/
|
||||||
WALLET_GOLD_ASSET_PROD("45b22e07-3cc4-41e5-944c-ebda65330e39"),
|
WALLET_GOLD_ASSET_PROD("656b398e-9713-4de9-8975-b6fac77a3f61"),
|
||||||
WALLET_GOLD_ASSET_DEVELOP("931e4d86-fde3-455e-b225-59f83ce30235");
|
WALLET_GOLD_ASSET_DEVELOP("931e4d86-fde3-455e-b225-59f83ce30235");
|
||||||
|
|
||||||
private final String topic;
|
private final String topic;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user