pendingTasks = new ConcurrentHashMap<>();
-
- // 任务ID生成器 (格式: {type}_{groupId}_{自增序号})
- private java.util.concurrent.atomic.AtomicLong taskIdGenerator = new java.util.concurrent.atomic.AtomicLong(1);
-
/**
- * 启动时加载配置缓存并恢复内存状态
+ * 启动时加载配置缓存
+ * 不再做 roundTasks/pendingTasks 内存恢复 —— 扫描任务启动后会自动从数据库接管
*/
@jakarta.annotation.PostConstruct
public void loadConfig() {
try {
- // 加载配置缓存
List configs = sysConfigMapper.selectList(null);
for (SysConfig config : configs) {
configCache.put(config.getCfgKey(), config.getCfgValue());
}
log.info("配置缓存加载完成,共 {} 条配置", configs.size());
-
- // 恢复进行中的局状态
- recoverRoundTasks();
-
- // 恢复延迟任务队列
- recoverPendingTasks();
-
} catch (Exception e) {
log.error("启动初始化失败: {}", e.getMessage(), e);
}
}
- /**
- * 从数据库恢复进行中的局状态
- */
- private void recoverRoundTasks() {
- try {
- List ongoingRounds = gameRoundMapper.selectList(
- new LambdaQueryWrapper()
- .lt(GameRound::getStatus, IGameService.STATUS_FINISHED));
-
- if (ongoingRounds.isEmpty()) {
- log.info("无进行中的局,无需恢复");
- return;
- }
-
- int bettingInterval = getConfigInt("betting_interval", 60);
-
- for (GameRound round : ongoingRounds) {
- RoundTask task = new RoundTask();
- task.setRoundId(round.getId());
- task.setGroupId(round.getGroupId());
-
- // 优先使用数据库中的endBetTime,否则根据startTime计算
- if (round.getEndBetTime() != null) {
- task.setEndBetTime(round.getEndBetTime());
- } else if (round.getStartTime() != null) {
- task.setEndBetTime(round.getStartTime().plusSeconds(bettingInterval));
- } else {
- // 兜底:使用配置的下注时长
- task.setEndBetTime(LocalDateTime.now().plusSeconds(bettingInterval));
- }
-
- roundTasks.put(round.getId(), task);
- }
-
- log.info("局状态恢复完成,共恢复 {} 个进行中的局", ongoingRounds.size());
- } catch (Exception e) {
- log.error("恢复局状态失败: {}", e.getMessage(), e);
- }
- }
-
- /**
- * 从数据库恢复延迟任务队列
- * 注:包括已过期的任务,过期任务会在processPendingTasks中立即执行
- */
- private void recoverPendingTasks() {
- try {
- // 数据库中残留的记录都是未执行的(执行成功后会立即删除),全部恢复
- List dbTasks = pendingTaskMapper.selectList(null);
-
- if (dbTasks == null || dbTasks.isEmpty()) {
- log.info("无待执行的延迟任务,无需恢复");
- return;
- }
-
- LocalDateTime now = LocalDateTime.now();
- int recovered = 0;
- int expiredCount = 0;
- for (PendingTask dbTask : dbTasks) {
- if (dbTask.getExecuteTime() == null) {
- log.warn("跳过executeTime为空的延迟任务: taskId={}", dbTask.getTaskId());
- continue;
- }
- PendingTaskInfo info = new PendingTaskInfo();
- info.setTaskId(dbTask.getTaskId());
- info.setType(dbTask.getType());
- info.setRoundId(dbTask.getRoundId());
- info.setGroupId(dbTask.getGroupId());
- info.setDigit(dbTask.getDigit());
- info.setExecuteTime(dbTask.getExecuteTime());
- pendingTasks.put(info.getTaskId(), info);
- recovered++;
- if (!dbTask.getExecuteTime().isAfter(now)) {
- expiredCount++;
- log.warn("恢复已过期任务,启动后立即执行: taskId={}, type={}, groupId={}, executeTime={}",
- dbTask.getTaskId(), dbTask.getType(), dbTask.getGroupId(), dbTask.getExecuteTime());
- }
- }
-
- log.info("延迟任务恢复完成,共恢复 {} 个待执行任务,其中 {} 个已过期将立即执行",
- recovered, expiredCount);
- } catch (Exception e) {
- log.error("恢复延迟任务失败: {}", e.getMessage(), e);
- }
- }
-
/**
* 获取配置值
*/
@@ -308,26 +213,102 @@ public class GameJob {
}
/**
- * 检查局超时(每10秒执行)
+ * 扫描下注超时局 —— 每 2 秒
+ * 条件:{@code status=0 (下注中) AND end_bet_time < NOW()}
*/
- @Scheduled(fixedDelay = 10000)
- public void checkRoundTimeout() {
- List ongoingRounds = gameRoundMapper.selectList(new LambdaQueryWrapper()
- .eq(GameRound::getStatus, IGameService.STATUS_BETTING));
+ @Scheduled(fixedDelay = 2000)
+ public void scanRoundTimeouts() {
+ List overdue = gameRoundMapper.selectList(
+ new LambdaQueryWrapper()
+ .eq(GameRound::getStatus, IGameService.STATUS_BETTING)
+ .lt(GameRound::getEndBetTime, LocalDateTime.now())
+ .last("LIMIT 50"));
- for (GameRound round : ongoingRounds) {
- // 检查是否超过接注时间
- RoundTask task = roundTasks.get(round.getId());
- if (task != null && task.getEndBetTime().isBefore(LocalDateTime.now())) {
- // 自动结束接注
- try {
- gameService.endBet(round.getGroupId(), 0L); // 0L表示系统自动触发
- // 触发开始发红包,延迟时间从配置读取
- int sendRpDelay = getConfigInt("send_rp_delay", 20);
- scheduleStartRp(round.getId(), round.getGroupId(), sendRpDelay);
- } catch (Exception e) {
- log.error("自动结束接注失败: roundId={}, error={}", round.getId(), e.getMessage());
+ for (GameRound round : overdue) {
+ try {
+ gameService.endBet(round.getGroupId(), 0L); // 0L 表示系统自动触发
+ } catch (Exception e) {
+ log.error("自动结束接注失败: roundId={}, error={}", round.getId(), e.getMessage(), e);
+ }
+ }
+ }
+
+ /**
+ * 扫描"封盘后到点开始发红包" —— 每 2 秒
+ * 条件:{@code status=1 (已封盘) AND start_rp_time IS NULL AND end_bet_time + send_rp_delay 秒 < NOW()}
+ */
+ @Scheduled(fixedDelay = 2000)
+ public void scanStartRpTimeouts() {
+ int sendRpDelay = getConfigInt("send_rp_delay", 20);
+ LocalDateTime threshold = LocalDateTime.now().minusSeconds(sendRpDelay);
+ List due = gameRoundMapper.selectList(
+ new LambdaQueryWrapper()
+ .eq(GameRound::getStatus, IGameService.STATUS_BET_CLOSED)
+ .isNull(GameRound::getStartRpTime)
+ .lt(GameRound::getEndBetTime, threshold)
+ .last("LIMIT 50"));
+
+ for (GameRound round : due) {
+ try {
+ onStartRp(round.getId(), round.getGroupId());
+ } catch (Exception e) {
+ log.error("延迟开始发红包失败: roundId={}, error={}", round.getId(), e.getMessage(), e);
+ }
+ }
+ }
+
+ /**
+ * 扫描"发包超时由机器人代发" —— 每 2 秒
+ * 条件:{@code status=2 (发红包中) AND first_rp_id IS NULL AND start_rp_time + auto_rp_timeout 秒 < NOW()}
+ */
+ @Scheduled(fixedDelay = 2000)
+ public void scanBotSendRpTimeouts() {
+ int autoRpTimeout = getConfigInt("auto_rp_timeout", 10);
+ LocalDateTime threshold = LocalDateTime.now().minusSeconds(autoRpTimeout);
+ List due = gameRoundMapper.selectList(
+ new LambdaQueryWrapper()
+ .eq(GameRound::getStatus, IGameService.STATUS_RP_SENDING)
+ .isNull(GameRound::getFirstRpId)
+ .isNotNull(GameRound::getStartRpTime)
+ .lt(GameRound::getStartRpTime, threshold)
+ .last("LIMIT 50"));
+
+ for (GameRound round : due) {
+ try {
+ botSendRp(round.getId(), round.getGroupId());
+ } catch (Exception e) {
+ log.error("机器人自动发包扫描执行失败: roundId={}, error={}", round.getId(), e.getMessage(), e);
+ }
+ }
+ }
+
+ /**
+ * 扫描"结算后自动开下一期" —— 每 2 秒
+ * 条件:{@code status=3 (已结算) AND auto_next=1 AND finish_time + 5 秒 < NOW()}
+ * 且本群当前无进行中局
+ */
+ @Scheduled(fixedDelay = 2000)
+ public void scanAutoNextTimeouts() {
+ int autoNextDelay = getConfigInt("auto_next_delay", 5);
+ LocalDateTime threshold = LocalDateTime.now().minusSeconds(autoNextDelay);
+ List finished = gameRoundMapper.selectList(
+ new LambdaQueryWrapper()
+ .eq(GameRound::getStatus, IGameService.STATUS_FINISHED)
+ .eq(GameRound::getAutoNext, 1)
+ .isNotNull(GameRound::getFinishTime)
+ .lt(GameRound::getFinishTime, threshold)
+ .last("LIMIT 50"));
+
+ for (GameRound round : finished) {
+ try {
+ // 仅当该群当前无进行中局时才开下一期
+ GameRound ongoing = gameService.getOngoingRound(round.getGroupId());
+ if (ongoing != null) {
+ continue;
}
+ onAutoNext(round.getGroupId());
+ } catch (Exception e) {
+ log.error("自动开下一期失败: groupId={}, error={}", round.getGroupId(), e.getMessage(), e);
}
}
}
@@ -339,224 +320,33 @@ public class GameJob {
public void resetDailyFakeUsers() {
fakeUserService.resetDailyActiveFakes();
}
- /**
- * 处理延迟任务队列(每秒执行)
- */
- @Scheduled(fixedDelay = 1000)
- public void processPendingTasks() {
- LocalDateTime now = LocalDateTime.now();
- for (Map.Entry entry : pendingTasks.entrySet()) {
- PendingTaskInfo task = entry.getValue();
- if (task.getExecuteTime() == null) {
- pendingTasks.remove(entry.getKey());
- deleteTaskFromDb(task.getTaskId());
- continue;
- }
- if (task.getExecuteTime().isBefore(now) || task.getExecuteTime().isEqual(now)) {
- boolean success = executeTask(task);
- if (success) {
- pendingTasks.remove(entry.getKey());
- deleteTaskFromDb(task.getTaskId());
- } else {
- // 失败时保留内存与数据库中的任务,5秒后再重试
- task.setExecuteTime(LocalDateTime.now().plusSeconds(5));
- updateTaskExecuteTimeInDb(task);
- log.warn("任务执行失败,保留任务待重试: taskId={}", task.getTaskId());
- }
- }
- }
- }
/**
- * 更新延迟任务的执行时间(失败重试场景)
- */
- private void updateTaskExecuteTimeInDb(PendingTaskInfo task) {
- try {
- PendingTask dbTask = pendingTaskMapper.selectOne(
- new LambdaQueryWrapper().eq(PendingTask::getTaskId, task.getTaskId()));
- if (dbTask != null) {
- dbTask.setExecuteTime(task.getExecuteTime());
- pendingTaskMapper.updateById(dbTask);
- }
- } catch (Exception e) {
- log.error("更新延迟任务执行时间失败: taskId={}, error={}", task.getTaskId(), e.getMessage());
- }
- }
-
- /**
- * 执行延迟任务
- *
- * @return true 表示执行成功(可清理);false 表示执行失败(需保留以重试)
- */
- private boolean executeTask(PendingTaskInfo task) {
- try {
- switch (task.getType()) {
- case "settle":
- return onSettle(task.getRoundId(), task.getGroupId(), task.getDigit());
- case "auto_next":
- return onAutoNext(task.getGroupId());
- case "start_rp":
- return onStartRp(task.getRoundId(), task.getGroupId());
- case "bot_send_rp":
- return botSendRp(task.getRoundId(), task.getGroupId());
- default:
- log.warn("未知任务类型: {}", task.getType());
- return false;
- }
- } catch (Exception e) {
- log.error("执行任务失败: taskId={}, error={}", task.getTaskId(), e.getMessage());
- return false;
- }
- }
- /**
- * 安排开始发红包
- */
- public String scheduleStartRp(Long roundId, Long groupId, int delaySeconds) {
- String taskId = "start_rp_" + groupId + "_" + taskIdGenerator.getAndIncrement();
- PendingTaskInfo task = new PendingTaskInfo();
- task.setTaskId(taskId);
- task.setType("start_rp");
- task.setRoundId(roundId);
- task.setGroupId(groupId);
- LocalDateTime executeTime = LocalDateTime.now().plusSeconds(delaySeconds);
- task.setExecuteTime(executeTime);
- pendingTasks.put(taskId, task);
- // 持久化到数据库
- saveTaskToDb(taskId, "start_rp", roundId, groupId, null, executeTime);
- log.info("安排{}秒后开始发红包: roundId={}", delaySeconds, roundId);
- return taskId;
- }
-
- /**
- * 安排自动结算
- */
- public String scheduleSettle(Long roundId, Long groupId, int digit, int delaySeconds) {
- String taskId = "settle_" + groupId + "_" + taskIdGenerator.getAndIncrement();
- PendingTaskInfo task = new PendingTaskInfo();
- task.setTaskId(taskId);
- task.setType("settle");
- task.setRoundId(roundId);
- task.setGroupId(groupId);
- task.setDigit(digit);
- LocalDateTime executeTime = LocalDateTime.now().plusSeconds(delaySeconds);
- task.setExecuteTime(executeTime);
- pendingTasks.put(taskId, task);
- // 持久化到数据库
- saveTaskToDb(taskId, "settle", roundId, groupId, digit, executeTime);
- log.info("安排{}秒后结算: taskId={}, roundId={}, digit={}", delaySeconds, taskId, roundId, digit);
- return taskId;
- }
-
- /**
- * 安排自动下一期
- */
- public String scheduleAutoNextTask(Long groupId, int delaySeconds) {
- String taskId = "auto_next_" + groupId + "_" + taskIdGenerator.getAndIncrement();
- PendingTaskInfo task = new PendingTaskInfo();
- task.setTaskId(taskId);
- task.setType("auto_next");
- task.setGroupId(groupId);
- LocalDateTime executeTime = LocalDateTime.now().plusSeconds(delaySeconds);
- task.setExecuteTime(executeTime);
- pendingTasks.put(taskId, task);
- // 持久化到数据库
- saveTaskToDb(taskId, "auto_next", null, groupId, null, executeTime);
- log.info("安排{}秒后自动开始下一期: groupId={}", delaySeconds, groupId);
- return taskId;
- }
-
- /**
- * 安排机器人发包
- */
- public String scheduleBotSendRp(Long roundId, Long groupId, int delaySeconds) {
- String taskId = "bot_send_rp_" + groupId + "_" + taskIdGenerator.getAndIncrement();
- PendingTaskInfo task = new PendingTaskInfo();
- task.setTaskId(taskId);
- task.setType("bot_send_rp");
- task.setRoundId(roundId);
- task.setGroupId(groupId);
- LocalDateTime executeTime = LocalDateTime.now().plusSeconds(delaySeconds);
- task.setExecuteTime(executeTime);
- pendingTasks.put(taskId, task);
- // 持久化到数据库
- saveTaskToDb(taskId, "bot_send_rp", roundId, groupId, null, executeTime);
- log.info("安排{}秒后机器人发包: roundId={}", delaySeconds, roundId);
- return taskId;
- }
-
- /**
- * 保存任务到数据库
- */
- private void saveTaskToDb(String taskId, String type, Long roundId, Long groupId, Integer digit, LocalDateTime executeTime) {
- try {
- PendingTask dbTask = new PendingTask();
- dbTask.setTaskId(taskId);
- dbTask.setType(type);
- dbTask.setRoundId(roundId);
- dbTask.setGroupId(groupId);
- dbTask.setDigit(digit);
- dbTask.setExecuteTime(executeTime);
- dbTask.setCreateTime(LocalDateTime.now());
- pendingTaskMapper.insert(dbTask);
- } catch (Exception e) {
- log.error("保存任务到数据库失败: taskId={}, error={}", taskId, e.getMessage());
- }
- }
-
- /**
- * 从数据库删除任务
- */
- private void deleteTaskFromDb(String taskId) {
- try {
- pendingTaskMapper.delete(new LambdaQueryWrapper()
- .eq(PendingTask::getTaskId, taskId));
- } catch (Exception e) {
- log.error("从数据库删除任务失败: taskId={}, error={}", taskId, e.getMessage());
- }
- }
-
- /**
- * 开始游戏后安排定时器
+ * 开始游戏后广播并打日志
*/
public void onGameStart(Long roundId, Long groupId, int intervalSeconds) {
- RoundTask task = new RoundTask();
- task.setRoundId(roundId);
- task.setGroupId(groupId);
- task.setEndBetTime(LocalDateTime.now().plusSeconds(intervalSeconds));
- roundTasks.put(roundId, task);
-
- // 广播开始下注
GameRound round = gameRoundMapper.selectById(roundId);
if (round != null) {
broadcastStartBet(groupId, round.getRoundNo());
}
-
log.info("游戏开始: roundId={}, {}秒后结束接注", roundId, intervalSeconds);
}
/**
- * 结束接注后安排发红包
+ * 结束接注后广播 + 通知白名单
+ * 延迟开始发红包由 {@link #scanStartRpTimeouts()} 接管
*/
public void onEndBet(Long roundId, Long groupId) {
- // 移除结束接注定时器
- roundTasks.remove(roundId);
-
- // 广播结束下注
GameRound round = gameRoundMapper.selectById(roundId);
if (round != null) {
broadcastEndBet(groupId, round.getRoundNo());
}
-
- // 通知白名单用户尾数试算完成
notifyWhiteUsers(roundId);
-
- // 安排延迟后开始发红包
- int sendRpDelay = getConfigInt("send_rp_delay", 20);
- scheduleStartRp(roundId, groupId, sendRpDelay);
}
/**
* 开始发红包
+ *
机器人超时发包由 {@link #scanBotSendRpTimeouts()} 接管
*/
public boolean onStartRp(Long roundId, Long groupId) {
try {
@@ -565,6 +355,13 @@ public class GameJob {
return true;
}
+ // 再次校验:避免重复推进状态机
+ if (round.getStatus() == null || round.getStatus() != IGameService.STATUS_BET_CLOSED) {
+ log.debug("本局{}当前状态非封盘中(status={}),跳过发红包开始",
+ roundId, round.getStatus());
+ return true;
+ }
+
// 更新局状态为开始发红包
round.setStatus(IGameService.STATUS_RP_SENDING);
round.setStartRpTime(LocalDateTime.now());
@@ -572,13 +369,9 @@ public class GameJob {
// 广播开始发红包
broadcastStartRp(groupId, round.getRoundNo());
-
- // 安排超时后如果没人发包则机器人自动发
- int autoRpTimeout = getConfigInt("auto_rp_timeout", 10);
- scheduleBotSendRp(roundId, groupId, autoRpTimeout);
return true;
} catch (Exception e) {
- log.error("开始发红包失败: roundId={}, error={}", roundId, e.getMessage());
+ log.error("开始发红包失败: roundId={}, error={}", roundId, e.getMessage(), e);
return false;
}
}
@@ -649,6 +442,7 @@ public class GameJob {
/**
* 开奖结算
+ *
自动开下一期由 {@link #scanAutoNextTimeouts()} 接管
*/
public boolean onSettle(Long roundId, Long groupId, int digit) {
try {
@@ -660,20 +454,10 @@ public class GameJob {
broadcastResult(groupId, digit, round.getRoundNo());
}
- // 检查是否自动开启下一期
- GameRound roundAfterSettle = gameRoundMapper.selectById(roundId);
- if (roundAfterSettle != null && roundAfterSettle.getAutoNext() == 1) {
- // 5秒后自动开始下一期
- scheduleAutoNextTask(groupId, 5);
- }
-
- // 清理任务
- roundTasks.remove(roundId);
-
log.info("局结算完成: roundId={}, digit={}", roundId, digit);
return true;
} catch (Exception e) {
- log.error("结算失败: roundId={}, error={}", roundId, e.getMessage());
+ log.error("结算失败: roundId={}, error={}", roundId, e.getMessage(), e);
return false;
}
}
@@ -787,9 +571,6 @@ public class GameJob {
return sb.toString().trim();
}
-
-
-
/**
* 自动开始下一期
*/
@@ -800,12 +581,12 @@ public class GameJob {
log.warn("自动开始下一期失败:startGame未返回局信息, groupId={}", groupId);
return false;
}
- // 复用与手动流程一致的逻辑:注册roundTasks监控 + 广播开始下注
+ // 复用与手动流程一致的逻辑:广播开始下注
int betWindowSeconds = getConfigInt("bet_window_seconds", 60);
onGameStart(round.getId(), groupId, betWindowSeconds);
return true;
} catch (Exception e) {
- log.error("自动开始下一期失败: groupId={}, error={}", groupId, e.getMessage());
+ log.error("自动开始下一期失败: groupId={}, error={}", groupId, e.getMessage(), e);
return false;
}
}
diff --git a/src/main/java/com/tailbet/mapper/PendingTaskMapper.java b/src/main/java/com/tailbet/mapper/PendingTaskMapper.java
deleted file mode 100644
index 49c32ce..0000000
--- a/src/main/java/com/tailbet/mapper/PendingTaskMapper.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package com.tailbet.mapper;
-
-import com.tailbet.model.entity.PendingTask;
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-import org.apache.ibatis.annotations.Mapper;
-
-/**
- * 延迟任务Mapper
- */
-@Mapper
-public interface PendingTaskMapper extends BaseMapper {
-}
diff --git a/src/main/java/com/tailbet/model/PendingTaskInfo.java b/src/main/java/com/tailbet/model/PendingTaskInfo.java
deleted file mode 100644
index 729b677..0000000
--- a/src/main/java/com/tailbet/model/PendingTaskInfo.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package com.tailbet.model;
-
-import lombok.Data;
-import java.time.LocalDateTime;
-
-/**
- * 延迟任务信息(内存缓存用)
- */
-@Data
-public class PendingTaskInfo {
- private String taskId;
- private String type;
- private Long roundId;
- private Long groupId;
- private Integer digit;
- private LocalDateTime executeTime;
-}
diff --git a/src/main/java/com/tailbet/model/RoundTask.java b/src/main/java/com/tailbet/model/RoundTask.java
deleted file mode 100644
index d764969..0000000
--- a/src/main/java/com/tailbet/model/RoundTask.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package com.tailbet.model;
-
-import lombok.Data;
-
-import java.time.LocalDateTime;
-
-/**
- * 局任务信息
- */
-@Data
-public class RoundTask {
- private Long roundId;
- private Long groupId;
- private LocalDateTime endBetTime;
- private LocalDateTime startRpTime;
-}
diff --git a/src/main/java/com/tailbet/model/entity/PendingTask.java b/src/main/java/com/tailbet/model/entity/PendingTask.java
deleted file mode 100644
index 3db8ad3..0000000
--- a/src/main/java/com/tailbet/model/entity/PendingTask.java
+++ /dev/null
@@ -1,53 +0,0 @@
-package com.tailbet.model.entity;
-
-import com.baomidou.mybatisplus.annotation.IdType;
-import com.baomidou.mybatisplus.annotation.TableId;
-import com.baomidou.mybatisplus.annotation.TableName;
-import lombok.Data;
-import java.time.LocalDateTime;
-
-/**
- * 延迟任务表
- */
-@Data
-@TableName("pending_task")
-public class PendingTask {
-
- @TableId(type = IdType.AUTO)
- private Long id;
-
- /**
- * 任务ID
- */
- private String taskId;
-
- /**
- * 任务类型: start_rp/settle/auto_next/bot_send_rp
- */
- private String type;
-
- /**
- * 局ID
- */
- private Long roundId;
-
- /**
- * 群ID
- */
- private Long groupId;
-
- /**
- * 开奖尾数(settle任务用)
- */
- private Integer digit;
-
- /**
- * 执行时间
- */
- private LocalDateTime executeTime;
-
- /**
- * 创建时间
- */
- private LocalDateTime createTime;
-}
diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml
index c9f7287..90347e3 100644
--- a/src/main/resources/application-dev.yml
+++ b/src/main/resources/application-dev.yml
@@ -29,8 +29,8 @@ mybatis-plus:
type-aliases-package: com.tailbet.entity
configuration:
map-underscore-to-camel-case: true
- log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
-# log-impl: org.apache.ibatis.logging.slf4j.Slf4jImpl
+# log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
+ log-impl: org.apache.ibatis.logging.slf4j.Slf4jImpl
global-config:
db-config:
@@ -64,9 +64,9 @@ openim:
jwt:
- secret: ${JWT_SECRET:4d19a5c2984044848df9bed721512f9f}
+ secret: ${JWT_SECRET:ecc6de473d6f4e0fbdaf5ea899fd2e26}
expiration: 604800000
logging:
level:
- com.tailbet: debug
+ com.tailbet: info
diff --git a/src/main/resources/sql/init.sql b/src/main/resources/sql/init.sql
index d243e70..c94d893 100644
--- a/src/main/resources/sql/init.sql
+++ b/src/main/resources/sql/init.sql
@@ -89,7 +89,10 @@ CREATE TABLE IF NOT EXISTS game_round (
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
UNIQUE KEY uk_group_round (group_id, round_no),
INDEX idx_status (status),
- INDEX idx_group_id (group_id)
+ INDEX idx_group_id (group_id),
+ INDEX idx_status_endbet (status, end_bet_time),
+ INDEX idx_status_startrp (status, start_rp_time),
+ INDEX idx_status_finishtime (status, finish_time)
) COMMENT '游戏局表';
-- 注单表
@@ -238,18 +241,21 @@ INSERT INTO sys_config (cfg_key, cfg_value, remark) VALUES
('bet_window_seconds', '60', '接注窗口时间(秒)'),
('fake_recv_seconds', '5', '托领取超时时间(秒)');
-CREATE TABLE `pending_task` (
- `id` BIGINT AUTO_INCREMENT PRIMARY KEY,
- `task_id` VARCHAR(64) NOT NULL COMMENT '任务ID',
- `type` VARCHAR(32) NOT NULL COMMENT 'start_rp/settle/auto_next/bot_send_rp',
- `round_id` BIGINT COMMENT '局ID',
- `group_id` BIGINT NOT NULL COMMENT '群ID',
- `digit` INT COMMENT '开奖尾数(settle任务用)',
- `execute_time` DATETIME NOT NULL COMMENT '执行时间',
- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
- INDEX `idx_execute_time` (`execute_time`),
- UNIQUE INDEX `idx_task_id` (`task_id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
+-- ====== 去内存 Map 重构后,pending_task 表已不再被应用写入,保留 DDL 仅作历史兼容参考 ======
+-- 实际生产如需清理,可执行:
+-- DROP TABLE IF EXISTS `pending_task`;
+-- CREATE TABLE `pending_task` (
+-- `id` BIGINT AUTO_INCREMENT PRIMARY KEY,
+-- `task_id` VARCHAR(64) NOT NULL COMMENT '任务ID',
+-- `type` VARCHAR(32) NOT NULL COMMENT 'start_rp/settle/auto_next/bot_send_rp',
+-- `round_id` BIGINT COMMENT '局ID',
+-- `group_id` BIGINT NOT NULL COMMENT '群ID',
+-- `digit` INT COMMENT '开奖尾数(settle任务用)',
+-- `execute_time` DATETIME NOT NULL COMMENT '执行时间',
+-- `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+-- INDEX `idx_execute_time` (`execute_time`),
+-- UNIQUE INDEX `idx_task_id` (`task_id`)
+-- ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- ====== 积分字段类型迁移:BIGINT → DECIMAL(20,2),与红包金额统一精度 ======
-- 历史BIGINT都是整数,DECIMAL(20,2)可无损容纳,无需特殊转换