package com.doumee.core.track;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;
/**
* 电车「车辆 → 活跃骑行订单」Redis 缓存,收口读写删,供开锁 / 还车 / 位置上报三处统一调用。
*
用途:位置上报(JT/T 808,秒级高频)时,用 bikeCode O(1) 取活跃订单,
* 替代每次查 member_rides,避免高频 DB 查询。
*
生命周期:
*
* - 电车开锁成功(→ 骑行中):{@link #set} 写入,带 24h TTL
* - 电车还车成功(→ 已还车):{@link #remove} 删除(覆盖 backBike / autoBackBike / forceBack 多入口)
* - 临停(→ 临停中):不删,期间照常写轨迹
*
* TTL 仅为兜底:正常还车会主动删;防还车异常分支漏删导致映射泄漏 → 已还车的车继续被当活跃写脏轨迹。
*
降级:本类方法不吞异常,由调用方 try-catch 降级(缓存是优化、非业务正确性来源,失败不得阻断主流程)。
*
value 以 JSON 字符串存取(与抖音 token 缓存一致,避开 RedisTemplate 序列化器对 POJO 的依赖)。
*
* @author rk
* @date 2026/06/25
*/
@Slf4j
@Component
public class RideActiveCache {
/** Redis key 前缀:车辆维度活跃订单映射 */
private static final String KEY_PREFIX = "ride:active:";
/** 缓存 TTL(秒):24 小时,覆盖最长骑行;兜底防还车漏删导致映射泄漏 */
private static final long TTL_SECONDS = 24L * 60L * 60L;
@Autowired
private RedisTemplate redisTemplate;
/** 拼 Redis key:ride:active:{bikeCode} */
private static String key(String bikeCode) {
return KEY_PREFIX + bikeCode;
}
/**
* 开锁成功时写入活跃订单映射(带 24h TTL)。
*
* @param bikeCode 车辆编码(缓存维度)
* @param ridesId 骑行订单主键 member_rides.id
* @param orderId 支付订单主键 member_rides.ordre_id → goodsorder.id(可 null)
*/
public void set(String bikeCode, String ridesId, String orderId) {
if (StringUtils.isBlank(bikeCode)) {
return;
}
RideActiveInfo info = new RideActiveInfo();
info.setRidesId(ridesId);
info.setOrderId(orderId);
redisTemplate.opsForValue().set(key(bikeCode), JSON.toJSONString(info), TTL_SECONDS, TimeUnit.SECONDS);
}
/**
* 位置上报时读取活跃订单映射。
*
* @param bikeCode 车辆编码
* @return 活跃订单载荷;无映射 / 非 String 值返回 null(调用方据此跳过轨迹写入)
*/
public RideActiveInfo get(String bikeCode) {
if (StringUtils.isBlank(bikeCode)) {
return null;
}
Object cached = redisTemplate.opsForValue().get(key(bikeCode));
if (cached instanceof String) {
return JSON.parseObject((String) cached, RideActiveInfo.class);
}
return null;
}
/**
* 还车成功时删除活跃订单映射。
*
* @param bikeCode 车辆编码
*/
public void remove(String bikeCode) {
if (StringUtils.isBlank(bikeCode)) {
return;
}
redisTemplate.delete(key(bikeCode));
}
}