0
点赞
收藏
分享

微信扫一扫

需求:要求定时执行接口任务

需求:要求定时执行接口任务

出现问题:集群环境下,定时任务重复执行。

由于服务都是集群部署,定时任务会在各个服务器上重复执行,轻则浪费服务器资源,重则造成数据紊乱。

quartz定时任务提供了集群方式,但还需为其创建数据库表。spring schedule可以实现简单轻量级的定时任务,但无法保证只执行一次。

通过探讨得知,可以使用redis的分布式锁保证spring schedule集群只执行一次。

@Component

@Configuration

@EnableScheduling

public class AutoConvertTask {

private static final Logger logger = LoggerFactory.getLogger(AutoConvertTask.class);

@Autowired

private RedisTemplate redisTemplate;

private static final String LOCK = "task-job-lock";

private static final String KEY = "tasklock";

@Scheduled(cron = "0 0 0 * * ? ")

public void autoConvertJob() {

boolean lock = false;

try {

lock = redisTemplate.opsForValue().setIfAbsent(KEY, LOCK);

logger.info("是否获取到锁:" + lock);

if (lock) {

List historyList = historyService.findTenDaysAgoUntreated();

for (GameHistory history : historyList) {

update(history);

}

} else {

logger.info("没有获取到锁,不执行任务!");

return;

}

} finally {

if (lock) {

redisTemplate.delete(KEY);

logger.info("任务结束,释放锁!");

} else {

logger.info("没有获取到锁,无需释放锁!");

}

}

}

}

redis分布式锁是通过setnx命令实现的。该命令的作用是,当往redis中存入一个值时,会先判断该值对应的key是否存在,如果存在则返回0,如果不存在,则将该值存入redis并返回1。根据这个特性,我们在程序中,每次都调用setIfAbsent(该方法是setnx命令的实现)方法,来模拟是否获取到锁,如果返回true,则说明该key值不存在,表示获取到锁;如果返回false,则说明该key值存在,已经有程序在使用这个key值了,从而实现了类似加锁的功能

总结:然后按照这段代码提示获取锁,当多个项目同时获取redis分布式锁,你用redis单线程的特性,所以当有一台服务器获取到锁的时候,其他的服务器就无法获取,则可以避免集群,分布式环境下重复执行的问题。


作者:三号小玩家




举报

相关推荐

0 条评论