feat: 切换定时任务至分布式调度底座

- 以执行账本和有界 Worker 承载重负载任务与故障接管

- 接入统一调度 Starter 并增加 MySQL 迁移、指标和回归测试
This commit is contained in:
2026-08-31 14:57:08 +08:00
parent 17ef189862
commit 8c174e5c02
66 changed files with 5348 additions and 545 deletions

View File

@@ -1,9 +1,8 @@
package tech.easyflow.starter;
import com.mybatisflex.core.FlexGlobalConfig;
import com.mybatisflex.core.audit.AuditMessage;
import com.mybatisflex.core.audit.AuditManager;
import com.mybatisflex.core.audit.ConsoleMessageCollector;
import com.mybatisflex.core.audit.MessageCollector;
import com.mybatisflex.core.tenant.TenantManager;
import com.mybatisflex.spring.boot.MyBatisFlexCustomizer;
import cn.dev33.satoken.stp.StpUtil;
@@ -11,18 +10,27 @@ import cn.dev33.satoken.exception.NotWebContextException;
import cn.dev33.satoken.exception.SaTokenContextException;
import cn.dev33.satoken.context.SaHolder;
import java.math.BigInteger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import tech.easyflow.common.entity.LoginAccount;
import tech.easyflow.common.satoken.util.SaTokenUtil;
import tech.easyflow.job.execution.SysJobExecutionContextHolder;
@Configuration
public class MybatisConfig implements MyBatisFlexCustomizer {
private static final Logger log = LoggerFactory.getLogger(MybatisConfig.class);
private static final int MAX_AUDIT_SQL_LENGTH = 2_000;
@Value("${easyflow.mybatis.sql-audit-enabled:false}")
private boolean sqlAuditEnabled;
@Override
public void customize(FlexGlobalConfig flexGlobalConfig) {
//开启审计功能
AuditManager.setAuditEnable(true);
// SQL 审计会同步格式化并输出每条语句,高频 Worker 轮询下必须显式开启。
AuditManager.setAuditEnable(sqlAuditEnabled);
// 统一使用标准 0/1 逻辑删除语义。
flexGlobalConfig.setNormalValueOfLogicDelete(0);
@@ -34,9 +42,25 @@ public class MybatisConfig implements MyBatisFlexCustomizer {
//取消控制台的 Banner 打印
flexGlobalConfig.setPrintBanner(false);
//设置 SQL 审计收集器
MessageCollector collector = new ConsoleMessageCollector();
AuditManager.setMessageCollector(collector);
if (sqlAuditEnabled) {
AuditManager.setMessageCollector(MybatisConfig::collectSafeAuditMessage);
}
}
/**
* 审计日志只记录参数化 SQL 模板,绝不读取 AuditMessage 中的参数或完整 SQL。
*/
private static void collectSafeAuditMessage(AuditMessage message) {
log.info("SQL audit: statement={}, elapsedMs={}, rows={}, sql={}",
message.getStmtId(), message.getElapsedTime(), message.getQueryCount(),
compactSqlTemplate(message.getQuery()));
}
private static String compactSqlTemplate(String sql) {
if (sql == null) return null;
String compact = sql.replaceAll("\\s+", " ").trim();
return compact.length() <= MAX_AUDIT_SQL_LENGTH
? compact : compact.substring(0, MAX_AUDIT_SQL_LENGTH) + "...";
}
/**
@@ -45,6 +69,12 @@ public class MybatisConfig implements MyBatisFlexCustomizer {
* @return 当前租户 ID 数组;没有请求登录上下文时返回 {@code null}
*/
private Object[] currentTenantIds() {
BigInteger scheduledTenantId = SysJobExecutionContextHolder.current()
.map(context -> context.tenantId())
.orElse(null);
if (scheduledTenantId != null) {
return new Object[]{scheduledTenantId};
}
try {
if (!SaHolder.getContext().isValid() || !StpUtil.isLogin()) {
return null;