重试定时任务,通过外部调度实现
package org.mengyun.tcctransaction.spring.recover; import org.mengyun.tcctransaction.SystemException; import org.mengyun.tcctransaction.recover.TransactionRecovery; import org.mengyun.tcctransaction.support.TransactionConfigurator; import org.quartz.Scheduler; import org.springframework.scheduling.quartz.CronTriggerFactoryBean; import org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean; /** * Created by changming.xie on 6/2/16. */ public class RecoverScheduledJob { private TransactionRecovery transactionRecovery; private TransactionConfigurator transactionConfigurator; private Scheduler scheduler; public void init() { try { MethodInvokingJobDetailFactoryBean jobDetail = new MethodInvokingJobDetailFactoryBean(); jobDetail.setTargetObject(transactionRecovery); jobDetail.setTargetMethod("startRecover"); jobDetail.setName("transactionRecoveryJob"); jobDetail.setConcurrent(false); jobDetail.afterPropertiesSet(); CronTriggerFactoryBean cronTrigger = new CronTriggerFactoryBean(); cronTrigger.setBeanName("transactionRecoveryCronTrigger"); cronTrigger.setCronExpression(transactionConfigurator.getRecoverConfig().getCronExpression()); cronTrigger.setJobDetail(jobDetail.getObject()); cronTrigger.afterPropertiesSet(); scheduler.scheduleJob(jobDetail.getObject(), cronTrigger.getObject()); scheduler.start(); } catch (Exception e) { throw new SystemException(e); } } public void setTransactionRecovery(TransactionRecovery transactionRecovery) { this.transactionRecovery = transactionRecovery; } public Scheduler getScheduler() { return scheduler; } public void setScheduler(Scheduler scheduler) { this.scheduler = scheduler; } public void setTransactionConfigurator(TransactionConfigurator transactionConfigurator) { this.transactionConfigurator = transactionConfigurator; } }
执行TransactionRecovery的startRecover方法,查找事物存储中,超过某一段设置时间一直没有修改的事物,执行恢复操作,更新或删除对应的状态和数据
package org.mengyun.tcctransaction.recover; import com.alibaba.fastjson.JSON; import org.apache.commons.lang3.exception.ExceptionUtils; import org.apache.log4j.Logger; import org.mengyun.tcctransaction.OptimisticLockException; import org.mengyun.tcctransaction.Transaction; import org.mengyun.tcctransaction.TransactionRepository; import org.mengyun.tcctransaction.api.TransactionStatus; import org.mengyun.tcctransaction.common.TransactionType; import org.mengyun.tcctransaction.support.TransactionConfigurator; import java.util.Calendar; import java.util.Date; import java.util.List; /** * Created by changmingxie on 11/10/15. */ public class TransactionRecovery { static final Logger logger = Logger.getLogger(TransactionRecovery.class.getSimpleName()); private TransactionConfigurator transactionConfigurator; public void startRecover() { List<Transaction> transactions = loadErrorTransactions(); recoverErrorTransactions(transactions); } private List<Transaction> loadErrorTransactions() { long currentTimeInMillis = Calendar.getInstance().getTimeInMillis(); TransactionRepository transactionRepository = transactionConfigurator.getTransactionRepository(); RecoverConfig recoverConfig = transactionConfigurator.getRecoverConfig(); return transactionRepository.findAllUnmodifiedSince(new Date(currentTimeInMillis - recoverConfig.getRecoverDuration() * 1000)); } private void recoverErrorTransactions(List<Transaction> transactions) { for (Transaction transaction : transactions) { if (transaction.getRetriedCount() > transactionConfigurator.getRecoverConfig().getMaxRetryCount()) { logger.error(String.format("recover failed with max retry count,will not try again. txid:%s, status:%s,retried count:%d,transaction content:%s", transaction.getXid(), transaction.getStatus().getId(), transaction.getRetriedCount(), JSON.toJSONString(transaction))); continue; } if (transaction.getTransactionType().equals(TransactionType.BRANCH) && (transaction.getCreateTime().getTime() + transactionConfigurator.getRecoverConfig().getMaxRetryCount() * transactionConfigurator.getRecoverConfig().getRecoverDuration() * 1000 > System.currentTimeMillis())) { continue; } try { transaction.addRetriedCount(); if (transaction.getStatus().equals(TransactionStatus.CONFIRMING)) { transaction.changeStatus(TransactionStatus.CONFIRMING); transactionConfigurator.getTransactionRepository().update(transaction); transaction.commit(); transactionConfigurator.getTransactionRepository().delete(transaction); } else if (transaction.getStatus().equals(TransactionStatus.CANCELLING) || transaction.getTransactionType().equals(TransactionType.ROOT)) { transaction.changeStatus(TransactionStatus.CANCELLING); transactionConfigurator.getTransactionRepository().update(transaction); transaction.rollback(); transactionConfigurator.getTransactionRepository().delete(transaction); } } catch (Throwable throwable) { if (throwable instanceof OptimisticLockException || ExceptionUtils.getRootCause(throwable) instanceof OptimisticLockException) { logger.warn(String.format("optimisticLockException happened while recover. txid:%s, status:%s,retried count:%d,transaction content:%s", transaction.getXid(), transaction.getStatus().getId(), transaction.getRetriedCount(), JSON.toJSONString(transaction)), throwable); } else { logger.error(String.format("recover failed, txid:%s, status:%s,retried count:%d,transaction content:%s", transaction.getXid(), transaction.getStatus().getId(), transaction.getRetriedCount(), JSON.toJSONString(transaction)), throwable); } } } } public void setTransactionConfigurator(TransactionConfigurator transactionConfigurator) { this.transactionConfigurator = transactionConfigurator; } }