实现方法:
1、通过zset数据结构实现任务排序,value=任务信息,score=任务触发时间(unix时间戳)
2、ZRANGEBYSCORE task_key -inf currentTIme, 获取当前时间以前的所有任务 (消费者定时每隔1秒执行一次获取)。
3、通过redis事务或者脚本实现 获取任务后同时删除任务ZREMRANGEBYSCORE task_kety -inf currentTIme, 解决多台机器重复消费任务的问题
value格式自己设计,举例子: 70#eating_job, 获取到value解析为userid=70的用户执行eating_job任务
附上获取任务redis代码(springboot)
public Set<String> zgetAndRemove(String key,Double min,Double max){
List<Object> txResults = redisTemplate.execute(new SessionCallback<List<Object>>() {
public List<Object> execute(RedisOperations operations) throws DataAccessException {
operations.multi();
operations.opsForZSet().rangeByScore(key,min,max);
operations.opsForZSet().removeRangeByScore(key,min,max);
return operations.exec();
}
});
Set<String> rs = null;
if(txResults != null && txResults.size() == 2){
rs = (Set<String>)txResults.get(0);
}
return rs;
}
/**
* 每秒从redis中获取当前要执行的任务
*/
@Scheduled(cron = "*/1 * * * * ?")
private void configureTasks() {
double min = 0d;
double max = System.currentTimeMillis() / 1000;
Set<String> task = redisUtil.zgetAndRemove(GlobalConst.DOG_TIMER_REDIS_KEY,min,max);
for(String member : task){
try {
logger.info("{}准备执行",member);
String[] data = member.split(GlobalConst.DOG_ACTION_REDIS_MEMBER_SPLIT);
if (data != null && data.length >= 2) {
String uid = data[0];
String action = data[1];
triggerAction(uid, action);
}
else{
logger.error("{}发现异常的定时任务数据",member);
}
}catch (Exception e){
logger.error("{}动作触发异常",member);
}
}
}