简单粗暴假假的处理一下分布式任务调度

原创
2018/04/10 14:04
阅读数 55

本来想用 qutarz 的分布式任务调度,奈何加了10来张表太费劲。

只想简单实现一下多个server下别重复或者说同时调用

而且就只个简单的任务   于是用spring自带的定时任务

但有个问题。集群环境会重复执行 且可能是同时执行。这不科学。

先前的考虑是

@ConditionalOnProperty(prefix="cn.com.ur",name="task-enable",havingValue="true")

当task-enable为true的时候才启任务。这样可以配合maven 部署的时候决定 哪台服务拥有任务

但有个问题。。多个开发 都默认task-enable=true 还是重复执行,导致某些业务可能会出错。

 

没办法 还是要集群环境调度不可控的问题。

spring boot  redis  代码如下

 

package cn.com.ur.mall.service.job;

import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.StringRedisTemplate;

/**
 * 分布式任务执行器
 * 
 * @author liucf
 *
 */
public class RedisLockTaskActuator {
	
	private Logger log = LoggerFactory.getLogger(this.getClass());
	
	/**
	 * 提前多少秒使锁失效
	 */
	private long reduceTime = 5;
	
	private String lockName = "LOCK";
	
	private StringRedisTemplate redisTemplate;
	
	public RedisLockTaskActuator(StringRedisTemplate redisTemplate) {
		super();
		this.redisTemplate = redisTemplate;
	}

	public long getReduceTime() {
		return reduceTime;
	}

	public void setReduceTime(long reduceTime) {
		this.reduceTime = reduceTime;
	}

	public String getLockName() {
		return lockName;
	}

	public void setLockName(String lockName) {
		this.lockName = lockName;
	}

	public StringRedisTemplate getRedisTemplate() {
		return redisTemplate;
	}

	public void setRedisTemplate(StringRedisTemplate redisTemplate) {
		this.redisTemplate = redisTemplate;
	}



	@FunctionalInterface
	public interface RedisLockTask{
		public void run();
	}

	public void execute(String key, long lockTime,RedisLockTask  redisLockTask) {
		execute(this.redisTemplate,key,lockTime,this.reduceTime,this.lockName,redisLockTask);
	}
	
	public void execute(StringRedisTemplate redisTemplate, String key, long lockTime,RedisLockTask  redisLockTask) {
		execute(redisTemplate,key,lockTime,this.reduceTime,this.lockName,redisLockTask);
	}

	public void execute(String key, long lockTime,String lockName,RedisLockTask  redisLockTask) {
		execute(this.redisTemplate,key,lockTime,this.reduceTime,this.lockName,redisLockTask);
	}
	
	public void execute(StringRedisTemplate redisTemplate, String key, long lockTime,String lockName,RedisLockTask  redisLockTask) {
		execute(redisTemplate,key,lockTime,this.reduceTime,lockName,redisLockTask);
	}
	
	public void execute(String key, long lockTime,long reduceTime,String lockName,RedisLockTask  redisLockTask) {
		execute(this.redisTemplate,key,lockTime,this.reduceTime,lockName,redisLockTask);
	}
	public void execute(StringRedisTemplate redisTemplate, String key, long lockTime,long reduceTime,String lockName,RedisLockTask  redisLockTask) {
		boolean lock = redisTemplate.opsForValue().setIfAbsent(key, lockName);
		//获取到锁
		if(lock) {
			//设置超时时间
			redisTemplate.expire(key, lockTime - reduceTime, TimeUnit.SECONDS);
			//执行
			redisLockTask.run();
		}else {
			//未获取到锁
			//为没么没有获取到锁
			long expire = redisTemplate.getExpire(key, TimeUnit.SECONDS);
			log.info("{}离一下次执行时间还有:{}秒", key,expire);
			if(expire == -1) {//未设置超时时间   //获取锁 设置超时时间失败
				redisTemplate.expire(key, lockTime - reduceTime, TimeUnit.SECONDS);
				//执行
				redisLockTask.run();
			}
		}
		
	}
}

 

使用代码如下

@Bean
	public RedisLockTaskActuator createRedisLockTaskActuator(StringRedisTemplate template) {
		return new RedisLockTaskActuator(template);
	}
        @Scheduled(cron="0 0/5 *  * * ? ")
	public void execute() {
		redisLockTaskActuator.execute("lockName", 5*60, ()->{
			//干点啥
		});
		
	}

误差时间 可能根据实际情况调整一下。主要是怕设置锁失效与获取锁的时间差太大,这样基本能满足不重复执行的需求

展开阅读全文
打赏
0
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部