Use redis distributed lock to solve the problem of repeated execution of spring schedule cluster deployment

product demand:

Connect to Tencent Cloud's real-time audio and video, pull Tencent Cloud's latest video in real time and use Ffmpeg video synthesis.

Encounter problems:

Since services are deployed in clusters , scheduled tasks will be executed repeatedly on each server, which will waste server resources at least, and cause data disorder at worst.

solution:

The quartz timing task provides a cluster mode, but a database table needs to be created for it. Spring schedule can implement simple and lightweight timing tasks, but it cannot guarantee that it will be executed only once.
After discussing with the architect, it is known that the distributed lock of redis can be used to ensure that the spring schedule cluster is only executed once.
Redis distributed locks are implemented through the setnx command. The function of this command is that when a value is stored in redis, it will first determine whether the key corresponding to the value exists, if it exists, it will return 0, if it does not exist, it will store the value in redis and return 1. According to this feature, we call the setIfAbsent (this method is the implementation of the setnx command) method every time in the program to simulate whether the lock is acquired. If it returns true, it means that the key value does not exist, indicating that the lock is acquired; if If it returns false, it means that the key value exists, and there is already a program using this key value, thus realizing a function similar to locking.

@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<GameHistory> historyList = historyService.findTenDaysAgoUntreated();
                for (GameHistory history : historyList) {
    
    
                    update(history);
                }
            } else {
    
    
                logger.info("没有获取到锁,不执行任务!");
                return;
            }
        } finally {
    
    
            if (lock) {
    
    
                redisTemplate.delete(KEY);
                logger.info("任务结束,释放锁!");
            } else {
    
    
                logger.info("没有获取到锁,无需释放锁!");
            }
        }

    }

}

This is the solution using Redis. There are many solutions on Github that use redis packaged into a framework.

Guess you like

Origin blog.csdn.net/chezong/article/details/123175685