package com.imutil.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.imutil.entity.PullWatermark; import org.apache.ibatis.annotations.Insert; import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Select; import java.time.OffsetDateTime; import java.util.List; /** * 补拉水位线 Mapper *

* upsert 用 PG ON CONFLICT,selectNeedCheck 按 updated_at 升序取最久未补拉的会话, * 配合补拉成功后推进 updated_at,实现会话轮询公平覆盖。 * * @author imutil */ public interface PullWatermarkMapper extends BaseMapper { /** * 水位线 upsert(PG ON CONFLICT) *

* 回调落库 / 补拉推进时调用。last_seq、last_time 取 GREATEST 不回退(防乱序回调回退游标), * updated_at 始终刷新为 now(驱动 selectNeedCheck 的轮询顺序)。 * * @param tenantId 租户ID * @param convId 会话ID * @param convType 会话类型 1=C2C 2=GROUP * @param lastSeq 最新消息 Seq * @param lastTime 最新消息时间 * @param now 当前时间(updated_at) * @return 影响行数(1=新增或更新) */ @Insert("INSERT INTO pull_watermark (tenant_id, conv_id, conv_type, last_seq, last_time, updated_at) " + "VALUES (#{tenantId}, #{convId}, #{convType}, #{lastSeq}, #{lastTime}, #{now}) " + "ON CONFLICT (tenant_id, conv_id) DO UPDATE SET " + "last_seq = GREATEST(pull_watermark.last_seq, EXCLUDED.last_seq), " + "last_time = GREATEST(pull_watermark.last_time, EXCLUDED.last_time), " + "updated_at = EXCLUDED.updated_at") int upsert(@Param("tenantId") String tenantId, @Param("convId") String convId, @Param("convType") int convType, @Param("lastSeq") long lastSeq, @Param("lastTime") OffsetDateTime lastTime, @Param("now") OffsetDateTime now); /** * 取最久未补拉的 N 个会话(按 updated_at 升序) *

* 补拉任务每轮调用,updated_at 最老的优先;补拉后 updated_at 推进到 now, * 该会话自然排到队尾,实现轮询式公平覆盖。 * * @param limit 每轮会话数 * @return 待补拉会话列表 */ @Select("SELECT tenant_id, conv_id, conv_type, last_seq, last_time, updated_at " + "FROM pull_watermark ORDER BY updated_at ASC LIMIT #{limit}") List selectNeedCheck(@Param("limit") int limit); }