后端架构更新

This commit is contained in:
super
2026-04-27 09:18:10 +08:00
parent 0caf62c3d2
commit 995e2ee65a
141 changed files with 6957 additions and 772 deletions
@@ -2,11 +2,11 @@ package com.nanri.aiimage.modules.ziniao.service;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.nanri.aiimage.common.exception.BusinessException;
import com.nanri.aiimage.config.ZiniaoProperties;
import com.nanri.aiimage.modules.ziniao.model.cache.ZiniaoSessionCacheDto;
import com.nanri.aiimage.modules.ziniao.model.cache.ZiniaoShopCacheDto;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
@@ -15,6 +15,7 @@ import java.util.List;
@Service
@RequiredArgsConstructor
@Slf4j
public class ZiniaoSessionCacheService {
private final StringRedisTemplate stringRedisTemplate;
@@ -22,62 +23,96 @@ public class ZiniaoSessionCacheService {
private final ZiniaoProperties ziniaoProperties;
public void saveSession(ZiniaoSessionCacheDto session) {
if (session == null || session.getSessionId() == null || session.getSessionId().isBlank()) {
return;
}
try {
stringRedisTemplate.opsForValue().set(buildSessionKey(session.getSessionId()), objectMapper.writeValueAsString(session), Duration.ofHours(ziniaoProperties.getSessionTtlHours()));
stringRedisTemplate.opsForValue().set(
buildSessionKey(session.getSessionId()),
objectMapper.writeValueAsString(session),
Duration.ofHours(ziniaoProperties.getSessionTtlHours()));
} catch (Exception ex) {
throw new BusinessException("保存紫鸟会话失败");
log.warn("[ziniao-session-cache] save session degraded sessionId={} msg={}",
session.getSessionId(), ex.getMessage());
}
}
public ZiniaoSessionCacheDto getSession(String sessionId) {
String raw = stringRedisTemplate.opsForValue().get(buildSessionKey(sessionId));
String raw;
try {
raw = stringRedisTemplate.opsForValue().get(buildSessionKey(sessionId));
} catch (Exception ex) {
log.warn("[ziniao-session-cache] get session degraded sessionId={} msg={}", sessionId, ex.getMessage());
return null;
}
if (raw == null || raw.isBlank()) {
return null;
}
try {
return objectMapper.readValue(raw, ZiniaoSessionCacheDto.class);
} catch (Exception ex) {
throw new BusinessException("读取紫鸟会话失败");
log.warn("[ziniao-session-cache] parse session degraded sessionId={} msg={}", sessionId, ex.getMessage());
return null;
}
}
public void saveShops(String sessionId, List<ZiniaoShopCacheDto> shops) {
try {
stringRedisTemplate.opsForValue().set(buildShopsKey(sessionId), objectMapper.writeValueAsString(shops), Duration.ofMinutes(ziniaoProperties.getShopsCacheMinutes()));
stringRedisTemplate.opsForValue().set(
buildShopsKey(sessionId),
objectMapper.writeValueAsString(shops),
Duration.ofMinutes(ziniaoProperties.getShopsCacheMinutes()));
} catch (Exception ex) {
throw new BusinessException("保存紫鸟店铺列表失败");
log.warn("[ziniao-session-cache] save shops degraded sessionId={} msg={}", sessionId, ex.getMessage());
}
}
public List<ZiniaoShopCacheDto> getShops(String sessionId) {
String raw = stringRedisTemplate.opsForValue().get(buildShopsKey(sessionId));
String raw;
try {
raw = stringRedisTemplate.opsForValue().get(buildShopsKey(sessionId));
} catch (Exception ex) {
log.warn("[ziniao-session-cache] get shops degraded sessionId={} msg={}", sessionId, ex.getMessage());
return List.of();
}
if (raw == null || raw.isBlank()) {
return List.of();
}
try {
return objectMapper.readValue(raw, new TypeReference<List<ZiniaoShopCacheDto>>() {});
} catch (Exception ex) {
throw new BusinessException("读取紫鸟店铺列表失败");
log.warn("[ziniao-session-cache] parse shops degraded sessionId={} msg={}", sessionId, ex.getMessage());
return List.of();
}
}
public void saveCurrentShop(String sessionId, ZiniaoShopCacheDto shop) {
try {
stringRedisTemplate.opsForValue().set(buildCurrentShopKey(sessionId), objectMapper.writeValueAsString(shop), Duration.ofHours(ziniaoProperties.getSessionTtlHours()));
stringRedisTemplate.opsForValue().set(
buildCurrentShopKey(sessionId),
objectMapper.writeValueAsString(shop),
Duration.ofHours(ziniaoProperties.getSessionTtlHours()));
} catch (Exception ex) {
throw new BusinessException("保存当前紫鸟店铺失败");
log.warn("[ziniao-session-cache] save current shop degraded sessionId={} msg={}", sessionId, ex.getMessage());
}
}
public ZiniaoShopCacheDto getCurrentShop(String sessionId) {
String raw = stringRedisTemplate.opsForValue().get(buildCurrentShopKey(sessionId));
String raw;
try {
raw = stringRedisTemplate.opsForValue().get(buildCurrentShopKey(sessionId));
} catch (Exception ex) {
log.warn("[ziniao-session-cache] get current shop degraded sessionId={} msg={}", sessionId, ex.getMessage());
return null;
}
if (raw == null || raw.isBlank()) {
return null;
}
try {
return objectMapper.readValue(raw, ZiniaoShopCacheDto.class);
} catch (Exception ex) {
throw new BusinessException("读取当前紫鸟店铺失败");
log.warn("[ziniao-session-cache] parse current shop degraded sessionId={} msg={}", sessionId, ex.getMessage());
return null;
}
}
@@ -101,6 +101,8 @@ public class ZiniaoShopIndexService {
return pendingResult("店铺索引信息不完整,请等待后台刷新");
}
boolean treatAsFresh = isFresh(entry) || shouldBypassFreshnessBecauseWhitelistFailure(entry);
if (!buildOpenStoreUrl) {
ZiniaoShopMatchResultVo vo = new ZiniaoShopMatchResultVo();
vo.setMatched(true);
@@ -110,8 +112,8 @@ public class ZiniaoShopIndexService {
vo.setPlatform(entry.getPlatform());
vo.setMatchedUserId(entry.getMatchedUserId());
vo.setOpenStoreUrl(null);
vo.setMatchStatus(isFresh(entry) ? MATCH_STATUS_MATCHED : MATCH_STATUS_STALE);
vo.setMatchMessage(isFresh(entry) ? null : "店铺索引已过保鲜期,请等待后台刷新");
vo.setMatchStatus(treatAsFresh ? MATCH_STATUS_MATCHED : MATCH_STATUS_STALE);
vo.setMatchMessage(treatAsFresh ? null : "店铺索引已过保鲜期,请等待后台刷新");
return vo;
}
@@ -145,8 +147,8 @@ public class ZiniaoShopIndexService {
vo.setMatchStatus(MATCH_STATUS_STALE);
vo.setMatchMessage("打开店铺链接暂时无法生成,请稍后重试");
} else {
vo.setMatchStatus(isFresh(entry) ? MATCH_STATUS_MATCHED : MATCH_STATUS_STALE);
vo.setMatchMessage(isFresh(entry) ? null : "店铺索引已过保鲜期,请等待后台刷新");
vo.setMatchStatus(treatAsFresh ? MATCH_STATUS_MATCHED : MATCH_STATUS_STALE);
vo.setMatchMessage(treatAsFresh ? null : "店铺索引已过保鲜期,请等待后台刷新");
}
return vo;
}
@@ -406,7 +408,19 @@ public class ZiniaoShopIndexService {
private ZiniaoShopMatchResultVo staleOrPendingResult(String defaultMessage, ZiniaoShopIndexEntryDto entry) {
if (entry != null && STATUS_STALE.equals(entry.getStatus())) {
ZiniaoShopMatchResultVo vo = new ZiniaoShopMatchResultVo();
vo.setMatched(false);
boolean hasReusableMatch = entry.getShopId() != null
&& !entry.getShopId().isBlank()
&& entry.getMatchedUserId() != null
&& entry.getMatchedUserId() > 0;
vo.setMatched(hasReusableMatch);
if (hasReusableMatch) {
vo.setShopId(entry.getShopId());
vo.setShopName(entry.getShopName());
vo.setCompanyName(entry.getCompanyName());
vo.setPlatform(entry.getPlatform());
vo.setMatchedUserId(entry.getMatchedUserId());
vo.setOpenStoreUrl(null);
}
vo.setMatchStatus(MATCH_STATUS_STALE);
vo.setMatchMessage(defaultMessage);
return vo;
@@ -538,6 +552,25 @@ public class ZiniaoShopIndexService {
return Instant.now().toEpochMilli() - entry.getLastRefreshedAt() <= freshWindowMillis;
}
private boolean shouldBypassFreshnessBecauseWhitelistFailure(ZiniaoShopIndexEntryDto entry) {
if (entry == null || !STATUS_ACTIVE.equals(entry.getStatus())) {
return false;
}
if (entry.getLastRefreshedAt() == null || entry.getLastRefreshedAt() <= 0) {
return false;
}
ZiniaoShopIndexRefreshCursorDto cursor = getRefreshCursor();
if (cursor == null || !"FAILED".equals(cursor.getStatus())) {
return false;
}
String message = cursor.getMessage();
if (message == null || !message.contains("白名单")) {
return false;
}
Long lastFinishedAt = cursor.getLastFinishedAt();
return lastFinishedAt != null && lastFinishedAt >= entry.getLastRefreshedAt();
}
private Duration resolveEntryTtl() {
Integer ttlHours = ziniaoProperties.getShopIndexEntryTtlHours();
if (ttlHours == null || ttlHours <= 0) {