使用Redis实现随机时间任务调度

随机时间任务调度,是指在某个随机时间之后,触发相应的任务。

比如某拼团电商场景中,用户发起拼团后,如果超过一小时没有人加入,会由系统强制添加虚拟用户,强制拼团成功。这个调度时间不能是固定的,而是随机散列分布的,否则会产生虚假感。

以下是用Redis实现的,利用的是redis中zset的排序功能。

首先,需要生成随机时间。在Java中可以用简单的随机算法,

    public Long forceGroupTimeout(OrderGroup group){
        Map probability=orderGroupConfig.getForceGroupProbability();
        int rd = random.nextInt(100);
        int delay; //结果数字
        if(rd < probability.get("10-30")){ //10-30分钟执行几率
            delay = 10+random.nextInt(20);
        }else if(rd < probability.get("30-60")){//30-60分钟执行几率
            delay = 30+random.nextInt(30);
        }else if(rd < probability.get("60-90")){//60-90分钟执行几率
            delay = 60+random.nextInt(30);
        }else{
            delay = 90+random.nextInt(30);//90-120分钟内强制执行
        }
        Long forceTime = System.currentTimeMillis()+(delay*60*1000)+60*60*1000;//此处添加一小时
        return forceTime ;
    }

其中,probability是一个随机几率的Map,在配置文件里配置如下

forceGroupProbability.10-30: 10

forceGroupProbability.30-60: 20

forceGroupProbability.60-90: 30

forceGroupProbability.90-120: 100

表示10-30分钟执行的几率是10%,30-60分钟执行的几率是20%,最后一个数可以不用填。

生成的这个时间戳就是我们假定一定时间后将要执行任务的时间,将任务id作为key,时间戳作为value保存到redis的zset中。

 

之后,建立每分钟执行的定时任务,使用zset范围取值方法取比当前时间戳小的任务id:

 Set result=zsetOperations.rangeByScore(getRedisKey(),0,currentTimestamp);

取出后根据任务id执行相应的任务,执行完后将对应的key移除即可。

zsetOperations.removeRangeByScore(getRedisKey(),0,currentTimestamp);

 

你可能感兴趣的:(Java)