Преглед на файлове

1、调整直播定时任务

yys преди 3 седмици
родител
ревизия
370d4f25c9

+ 10 - 1
fs-common/src/main/java/com/fs/common/config/TenantKeyRedisSerializer.java

@@ -53,6 +53,15 @@ public class TenantKeyRedisSerializer extends StringRedisSerializer {
 
     @Override
     public String deserialize(byte[] bytes) {
-        return super.deserialize(bytes); // 保持原样
+        String key = super.deserialize(bytes);
+        if (key != null && key.startsWith(PREFIX)) {
+            // 剥离 "tenantid:xxx:" 前缀,使 keys() 返回干净的業務 key,
+            // 后续作为参数再次传入 redisTemplate 操作时 serialize 会重新加上前缀。
+            int idx = key.indexOf(SEPARATOR, PREFIX.length());
+            if (idx > 0) {
+                return key.substring(idx + 1);
+            }
+        }
+        return key;
     }
 }

+ 12 - 1
fs-live-app/src/main/java/com/fs/live/datasource/TenantDataSourceManager.java

@@ -4,6 +4,8 @@ import com.alibaba.druid.pool.DruidDataSource;
 import com.fs.framework.datasource.DynamicDataSource;
 import com.fs.framework.datasource.DynamicDataSourceContextHolder;
 import com.fs.tenant.domain.TenantInfo;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.stereotype.Component;
 
 import javax.annotation.Resource;
@@ -19,6 +21,8 @@ import java.util.concurrent.ConcurrentHashMap;
 @Component
 public class TenantDataSourceManager {
 
+    private static final Logger log = LoggerFactory.getLogger(TenantDataSourceManager.class);
+
     @Resource
     private DynamicDataSource dynamicDataSource;
 
@@ -34,7 +38,14 @@ public class TenantDataSourceManager {
                 if (!TENANT_DS_CACHE.containsKey(tenantKey)) {
                     DataSource ds = createTenantDataSource(tenantInfo);
                     TENANT_DS_CACHE.put(tenantKey, ds);
-                    getResolvedDataSources().put(tenantKey, ds);
+                    Map<Object, DataSource> resolved = getResolvedDataSources();
+                    resolved.put(tenantKey, ds);
+                    // 验证注册是否成功
+                    DataSource verify = resolved.get(tenantKey);
+                    log.info("[TenantDS] 注册数据源: key={}, url={}, registered={}, resolvedDS size={}",
+                            tenantKey, tenantInfo.getDbUrl(),
+                            verify != null ? "SUCCESS" : "FAILED",
+                            resolved.size());
                 }
             }
         }

+ 16 - 5
fs-live-app/src/main/java/com/fs/live/task/Task.java

@@ -7,8 +7,10 @@ import com.alibaba.fastjson.JSONObject;
 import com.fs.common.constant.LiveKeysConstant;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.redis.RedisCache;
+import com.fs.common.utils.SecurityUtils;
 import com.fs.common.utils.StringUtils;
 import com.fs.framework.aspectj.lock.DistributeLock;
+import com.fs.framework.datasource.DynamicDataSourceContextHolder;
 import com.fs.erp.service.FsJstAftersalePushService;
 import com.fs.his.service.IFsUserService;
 import com.fs.live.domain.*;
@@ -299,13 +301,16 @@ public class Task {
             redisCache.redisTemplate.opsForZSet()
                     .removeRangeByScore(liveKey, 0, currentTime);
             try {
+                // 从 key(如 live:red_task:129)中提取 liveId
+                String liveIdStr = liveKey.substring(liveKey.lastIndexOf(':') + 1);
+                Long liveId = Long.valueOf(liveIdStr);
                 // 广播红包关闭消息
                 SendMsgVo sendMsgVo = new SendMsgVo();
-                sendMsgVo.setLiveId(Long.valueOf(liveKey));
+                sendMsgVo.setLiveId(liveId);
                 sendMsgVo.setCmd("red");
                 sendMsgVo.setStatus(-1);
-                liveService.asyncToCacheLiveConfig(Long.parseLong(liveKey));
-                webSocketServer.broadcastMessage(Long.valueOf(liveKey), JSONObject.toJSONString(R.ok().put("data", sendMsgVo)));
+                liveService.asyncToCacheLiveConfig(liveId);
+                webSocketServer.broadcastMessage(liveId, JSONObject.toJSONString(R.ok().put("data", sendMsgVo)));
             } catch (Exception e) {
                 log.error("更新红包状态异常", e);
             }
@@ -524,6 +529,10 @@ public class Task {
 
     @PostConstruct
     public void initLiveDatasOnStartup() {
+        if (saasTaskEnabled) {
+            log.info("SaaS模式跳过启动时点赞数据初始化,由租户定时任务 syncLiveDataToDB 处理");
+            return;
+        }
         log.info("项目启动,开始初始化直播点赞数据...");
         try {
             List<LiveData> liveDatas = liveDataService.getAllLiveDatas();
@@ -653,10 +662,12 @@ public class Task {
         Set<String> keys = redisCache.redisTemplate.keys(String.format(LIVE_COUPON_NUM, "*"));
         if (keys != null && !keys.isEmpty()) {
             for (String key : keys) {
-                Object o = redisCache.redisTemplate.opsForValue().get(String.format(LIVE_COUPON_NUM, key));
+                Object o = redisCache.getCacheObject(key);
                 if (o != null) {
+                    // key 格式: live:coupon:num:5,提取末尾的优惠券ID
+                    String couponIdStr = key.substring(key.lastIndexOf(':') + 1);
                     LiveCouponIssue updateEntity = new LiveCouponIssue();
-                    updateEntity.setId(Long.valueOf(key));
+                    updateEntity.setId(Long.valueOf(couponIdStr));
                     updateEntity.setRemainCount(Long.parseLong(o.toString()));
                     liveCouponIssueService.updateLiveCouponIssue(updateEntity);
                 }

+ 22 - 9
fs-live-app/src/main/java/com/fs/live/task/TenantTaskRunner.java

@@ -66,9 +66,10 @@ public class TenantTaskRunner {
     public void runForEachTenant(String taskName, Runnable action) {
         List<TenantInfo> tenants = getValidTenants();
         if (tenants == null || tenants.isEmpty()) {
-            log.debug("[SaaS Live Task] 无有效租户,跳过任务: {}", taskName);
+            log.info("[SaaS Live Task] 无有效租户,跳过任务: {}", taskName);
             return;
         }
+        log.info("[SaaS Live Task] 开始执行任务={}, 有效租户数={}", taskName, tenants.size());
         // 并行提交所有租户任务,等待全部完成
         List<Future<?>> futures = new java.util.ArrayList<>(tenants.size());
         for (TenantInfo tenant : tenants) {
@@ -97,12 +98,18 @@ public class TenantTaskRunner {
             query.setStatus(1);
             List<TenantInfo> tenants = tenantInfoService.selectTenantInfoList(query);
             if (tenants == null || tenants.isEmpty()) {
+                log.info("[SaaS Live Task] 主库中无status=1的租户");
                 return Collections.emptyList();
             }
             Date now = new Date();
-            return tenants.stream()
+            List<TenantInfo> valid = tenants.stream()
                     .filter(t -> t.getExpireTime() == null || !t.getExpireTime().before(now))
                     .collect(Collectors.toList());
+            log.info("[SaaS Live Task] 租户查询结果: total={}, valid={}", tenants.size(), valid.size());
+            return valid;
+        } catch (Exception e) {
+            log.error("[SaaS Live Task] 查询租户列表失败", e);
+            return Collections.emptyList();
         } finally {
             DynamicDataSourceContextHolder.clearDataSourceType();
         }
@@ -118,19 +125,25 @@ public class TenantTaskRunner {
 
             // 检查租户是否开通了直播功能(live 表是否有数据)
             if (!isLiveModuleEnabled(tenant)) {
-                log.error("[SaaS Live Task] 租户 tenantCode={} 未开通直播功能,跳过任务: {}",
+                log.warn("[SaaS Live Task] 租户 tenantCode={} 未开通直播功能,跳过任务: {}",
                         tenant.getTenantCode(), taskName);
                 return;
             }
 
-            // 加载租户项目配置
-            SysConfig cfg = sysConfigMapper.selectConfigByConfigKey("projectConfig");
-            if (cfg != null && StringUtils.isNotBlank(cfg.getConfigValue())) {
-                TenantConfigContext.set(JSONObject.parseObject(cfg.getConfigValue()));
-            } else {
+            // 加载租户项目配置(容错:租户库可能没有 sys_config 表)
+            try {
+                SysConfig cfg = sysConfigMapper.selectConfigByConfigKey("projectConfig");
+                if (cfg != null && StringUtils.isNotBlank(cfg.getConfigValue())) {
+                    TenantConfigContext.set(JSONObject.parseObject(cfg.getConfigValue()));
+                } else {
+                    TenantConfigContext.set(null);
+                }
+                ProjectConfig.loadTenantConfigsFromContext();
+            } catch (Exception e) {
+                log.error("[SaaS Live Task] 租户 {} 加载项目配置失败, 使用默认配置: {}",
+                        tenant.getTenantCode(), e.getMessage());
                 TenantConfigContext.set(null);
             }
-            ProjectConfig.loadTenantConfigsFromContext();
 
             // 设置租户 SecurityContext,让 TenantKeyRedisSerializer 自动拼租户前缀
             SecurityContextHolder.getContext().setAuthentication(