您的位置:首页 > 其它

配合长时间定时任务,立即执行该定时任务的思路

2017-09-19 17:53 218 查看
业务场景:

订单支付成功时,订单信息需要给银行系统同步,由于不能保证银行返回信息的时间,所以使用队列进行同步,并且用spring的定时任务执行。

需求:

订单支付成功时立即执行一次同步任务,如果失败,则没半小时执行一次同步任务,直至同步成功。

问题:

spring定时任务定为半小时,订单成功支付时,无法立即执行任务,只能等0-30分钟后执行同步任务,所以需要做一个功能,在订单支付成功的时候,调用一次同步任务。

解决方案:

在服务启动时,初始化一个A线程,该线程每隔N秒扫描一次任务集合,集合中存放着某个任务,扫描到就执行任务。然后在订单支付成功时,在将订单放入队列后,接着将订单放入任务集合,由A线程扫描并执行。

支付成功后代码:

BizLogger.info("订单支付成功!!!");
Singleton.put(SpdbRateTask.class);


Singleton:

import java.util.concurrent.ConcurrentHashMap;

public class Singleton {
private static ConcurrentHashMap<String,Class> map = new ConcurrentHashMap<String,Class>();
public static ConcurrentHashMap<String,Class> getMap(){
return map;
}

public static void put(Class clazz){
map.put(clazz.getCanonicalName(), clazz);
}
}


初始化线程任务:

import java.util.Iterator;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ConcurrentHashMap;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import org.springframework.web.context.support.WebApplicationContextUtils;
import com.jniu.app.task.ExcutTask;
import com.jniu.app.util.Singleton;
import com.jniu.bas.context.Context;
import com.jniu.bas.log4j.logger.BizLogger;

public class ProjectInit implements ServletContextListener {
private ConcurrentHashMap<String, Class> map = Singleton.getMap();

/**
* 初始化学校缓存
*/
@Override
public void contextInitialized(final ServletContextEvent sce) {
// 初始化当前上下文
Context ctx = Context.createContext("currentContext", null);
Context.pushCurrentContext(ctx);
TimerTask task = new TimerTask() {
@Override
public void run() {
Iterator<Map.Entry<String, Class>> it = map.entrySet().iterator();
ExcutTask t = null;
try {
Thread.sleep(3000);//任务不多,且不是很频繁,队列使用的是redis的list,为了防止定时任务执行时redis中还没有数据,这里延迟三秒
while (it.hasNext()) {
Map.Entry<String, Class> entry = it.next();
BizLogger.info("项目任务"+entry.getValue().getCanonicalName()+"执行开始");
t = ((ExcutTask) WebApplicationContextUtils.getWebApplicationContext(sce.getServletContext()).getBean(entry.getValue()));
t.a();
BizLogger.info("项目任务"+t.getClass().getCanonicalName()+"执行完成");
it.remove();
}
} catch (Exception e) {
e.printStackTrace();
BizLogger.info("项目任务"+t.getClass().getCanonicalName()+"执行失败");
}
}
};
Timer timer = new Timer();
long delay = 0;
long intevalPeriod = 10 * 1000;//每十秒检查一遍任务集合
timer.scheduleAtFixedRate(task, delay, intevalPeriod);
}

/**
* 销毁工作
*/
@Override
public void contextDestroyed(ServletContextEvent sce) {
// TODO Auto-generated method stub
}
}


spring定时任务:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import com.jniu.app.constans.Constans;
import com.jniu.app.service.SpdbOrderService;
import com.jniu.bas.log4j.logger.BizLogger;
import com.jniu.bas.result.ResultBean;

@Service
public class SpdbRateTask implements ExcutTask{
@Autowired
RedisTemplate<String, Object> redisTemplate;
@Autowired
SpdbOrderService spdbOrderService;

public void a(){
String t = null;
ResultBean resultBean = null;
try {
long size = redisTemplate.opsForList().size(Constans.SPDB_RATE_QUEUE);
if(size>0){
for(int i=0;i<size;i++){
t = (String)redisTemplate.opsForList().rightPop(Constans.SPDB_RATE_QUEUE);
if(t!=null){
resultBean = spdbOrderService.transDetailObtain(t);
if(!resultBean.isSuccess()){
redisTemplate.opsForList().leftPush(Constans.SPDB_RATE_QUEUE, t);
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
if(t!=null)
redisTemplate.opsForList().leftPush(Constans.SPDB_RATE_QUEUE, t);
BizLogger.info(resultBean.getMessage());
}
}

@Override
public String toString() {
return "SpdbRateTask-----name";
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息