Files
tencent-im-util/src/main/java/com/imutil/service/impl/PartitionServiceImpl.java
T
yixiongandClaude 8c9037fc4f fix: 跨租户授权联调修复 + 新增分区自建模块
- CrossTenantServiceImpl: 有效期判断改用 apply("start_at <= now()"),规避
  OffsetDateTime 绑定 timestamptz 比较异常(见实施记录 6.5)
- CallbackServiceImpl: 集成 C2C 跨租户授权检查(额外分发+审计+is_cross_tenant),
  提取 enqueueIfConfigured
- 新增 PartitionService/Task: im_message 按月 RANGE 分区滚动建表
  (当月+下月,@Init 启动自检 + 每日 0:10)
- 新增 CrossTenantService: 正反向授权匹配 + 跨租户审计

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-08 23:56:32 +08:00

74 lines
2.7 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package com.imutil.service.impl;
import com.imutil.mapper.PartitionMapper;
import com.imutil.service.PartitionService;
import lombok.extern.slf4j.Slf4j;
import org.noear.solon.annotation.Component;
import org.noear.solon.annotation.Init;
import org.noear.solon.annotation.Inject;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
/**
* im_message 分区管理服务实现
* <p>
* 每次建当月+下月分区(CREATE TABLE IF NOT EXISTS 幂等),保证:
* - 启动时当月分区就绪(init.sql 仅建了 default 兜底分区)
* - 跨月前下月分区已存在,消息不落 default 分区(避免查询性能退化)
* 分区按自然月 RANGE(msg_time)+08 时区边界。
*
* @author imutil
*/
@Slf4j
@Component
public class PartitionServiceImpl implements PartitionService {
private static final ZoneId ZONE = ZoneId.of("+08");
private static final DateTimeFormatter MONTH_FMT = DateTimeFormatter.ofPattern("yyyyMM");
/** PG timestamptz 字面量格式:2026-07-01 00:00:00+08:00 */
private static final DateTimeFormatter TS_FMT = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ssxxx");
@Inject
private PartitionMapper partitionMapper;
/**
* 应用启动后自检一次:首次启动当月分区缺失则补建
*/
@Init
public void init() {
try {
createCurrentAndNextMonth();
log.info("启动分区自检完成(当月+下月)");
} catch (Throwable e) {
log.error("启动分区自检异常", e);
}
}
@Override
public void createCurrentAndNextMonth() {
ZonedDateTime now = ZonedDateTime.now(ZONE);
ensureMonth(now.getYear(), now.getMonthValue());
// 下月:用 plusMonths 计算避免年底跨月
ZonedDateTime next = now.plusMonths(1);
ensureMonth(next.getYear(), next.getMonthValue());
}
/**
* 确保指定年月的分区存在(不存在则创建,幂等)
*/
private void ensureMonth(int year, int month) {
// 用 YearMonth 拼表名与边界,规避 1月/12月 跨年的日历计算坑
java.time.YearMonth ym = java.time.YearMonth.of(year, month);
String name = "im_message_" + ym.format(MONTH_FMT);
ZonedDateTime start = ym.atDay(1).atStartOfDay(ZONE);
ZonedDateTime end = ym.plusMonths(1).atDay(1).atStartOfDay(ZONE);
String sql = "CREATE TABLE IF NOT EXISTS " + name +
" PARTITION OF im_message FOR VALUES FROM ('" +
start.format(TS_FMT) + "') TO ('" + end.format(TS_FMT) + "')";
partitionMapper.execute(sql);
log.debug("分区就绪 {}", name);
}
}