三分钟带你领略Scheduled + Redis解决分布式定时问题

一.任务需求

***需求:***根据固定时间,主动获取本地数据库未推送的数据,然后将这些数据通过远程向某供应商推送。


二.定时任务代码

    @Resource
    private RedisLock redisLock;

    @Resource
    private RemoteInitiativeAeService initiativeAeService;


    /**
     * 主动拉取未读数据 如果数据不为空 主动推送
     * 拉取/推送时间 每天凌晨1点执行一次
     */
    @Scheduled(cron = "0 0 1 * * ?") //每天凌晨1点执行一次
    public void getBatchVaristor() {

        //获取当前类名 + 当前方法名
        String timerName = this.getClass().getName()
                + Thread.currentThread().getStackTrace()[1].getMethodName();
        //如果当前已经持有锁 结束 否则 设置过期时间 为 23小时59分钟
        if (redisLock.requireLock(timerName, 86340)) {
            return;
        }
        //查询 未推送过的原材料检验-压敏电阻
        List<AeRaiVaristorVO> raiVaristorVo = aeRaiVaristorMapper.selectNoReadVaristor();
        //如果存在未读数据 调用远程接口 主动推送
        if (StringUtils.isNotEmpty(raiVaristorVo)) {
            if (initiativeAeService.addAeVaristor(raiVaristorVo).checkAndGet() == 0) {
                throw new CustomException("推送错误! 数据0条!");
            }
        }
        //使用stream流 过滤出刚刚推送的Id
        List<Long> varistorIds = raiVaristorVo.stream().
                map(AeRaiVaristorVO::getId).collect(Collectors.toList());
        //根据Id 将这些数据修改为 已推送 避免下次重复推送
        aeRaiVaristorMapper.updateVaristorIsRead(varistorIds);
    }


代码分析:

1.获取当前类名 + 当前方法名 作为key

2.判断当前是否已经持有锁 说白了 就是是否存在重复执行 避免集群环境出现多次执行

3.查询 未推送过的原材料检验-压敏电阻

4.判断如果存在 数据 调用远程接口 主动推送

5.使用stream流 过滤出刚刚推送成功的Id

6.根据Id 将这些数据修改为 已推送 避免下次重复推送


三.Redis 代码逻辑

/**
     * redis 任务锁key的前缀
     */
    public static final String REDIS_LOCK_KEY = "com:guodian:job";


    @Resource
    private RedisTemplate<String, Object> redisTemplate;


    /**
     * 判断是否有锁。有 返回true 无 设置一定有效期锁 并 返回 false
     * @param lockName key
     * @param timeout 锁的有效期时间
     * @return 是否持有锁
     */
    public  boolean requireLock(String lockName, Long timeout) {
        String key = REDIS_LOCK_KEY + lockName;
        if (StringUtils.isNull(redisTemplate.getExpire(key))){
            redisTemplate.expire(key,timeout, TimeUnit.SECONDS); //时间单位为秒 可以设置小时和天
            return false;
        }
        return true;
    }



    /**
     * 判断是否有锁。有 返回true 无 设置有效时间截止点 并 返回 false
     * @param lockName key
     * @param date 锁的有效时间截止点
     * @return 是否持有锁
     */
    public boolean requireLock(String lockName, Date date) {
        String key = REDIS_LOCK_KEY + lockName;
        if (StringUtils.isNull(redisTemplate.getExpire(key))){
            redisTemplate.expireAt(key,date);
            return false;
        }
        return true;
    }

代码分析:

1.这里有两个方法 第一个方法:判断是否有锁。有 返回true 无 设置一定有效期锁 并 返回 false

第二个方法 :判断是否有锁。有 返回true 无 设置有效时间截止点 并 返回 false


三.远程调用

/**
 * @Author wufushan
 * @Date 2022/4/20 15:14
 * @Version 1.0
 */
@FeignClient(name = "remoteInitiativeAeService", url = "http://localhost:8080",fallbackFactory = RemoteGetUserFactory.class )
public interface RemoteInitiativeAeService {


    /**
     * 主动推送压敏电阻信息
     * @param raiVaristorVo 压敏电阻参数
     * @return 推送数量
     */
    @PostMapping("/initiative/aeVaristor")
    R<Integer> addAeVaristor(@Param("raiVaristorVo") List<AeRaiVaristorVO> raiVaristorVo);

}

四.熔断代码-hystrix

/**
 * @Author wfs
 * @Date 2022/4/20 15:15
 * @Version 1.0
 */
public class RemoteInitiativeAeFactory implements FallbackFactory<RemoteInitiativeAeService> {

    private static final Logger log = LoggerFactory.getLogger(RemoteInitiativeAeService.class);


    @Override
    public RemoteInitiativeAeService create(Throwable throwable) {
        log.info("远程WebSocket服务调用失败!{}", throwable.getMessage());

        return new RemoteInitiativeAeService() {

            @Override
            public R<Integer> addAeVaristor(List<AeRaiVaristorVO> raiVaristorVo) {
                return R.fail("主动推送压敏电阻数据失败!!");
            }
        };
    }
}

五.远程调用及跨模块调用 想看更详细的 请点击!!

远程调用跨服务+跨模块超详细

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一只可爱的委屈翁

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值