重试定时任务,通过外部调度实现

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;
}
}

TCC细读 - 3 恢复流程的更多相关文章

  1. TCC细读 - 1 例子流程

    http://www.iocoder.cn/categories/TCC-Transaction/ https://github.com/changmingxie/tcc-transaction 细读 ...

  2. hbase-数据恢复流程

    引用<https://blog.csdn.net/nigeaoaojiao/article/details/54909921> hlog介绍: hlog构建: 从图中可以看出,对于一个hl ...

  3. ASA密码恢复流程

    1.建立console连接2.重启启动安全设备 3.进入ROMMMON模式出现Use BREAK or ESC to interrupt boot字样时,按下ESC键进入ROMMON模式.4.设置RO ...

  4. TCC细读 - 2 核心实现

    TCC,基于业务层面的事物定义,粒度完全由业务自己控制,本质上还是补偿的思路,它把事物运行过程分为try-confirm-cancel阶段,每个阶段逻辑由业务代码控制 业务活动管理器控制业务活动的一致 ...

  5. 基于Redo Log和Undo Log的MySQL崩溃恢复流程

    在之前的文章「简单了解InnoDB底层原理」聊了一下MySQL的Buffer Pool.这里再简单提一嘴,Buffer Pool是MySQL内存结构中十分核心的一个组成,你可以先把它想象成一个黑盒子. ...

  6. elasticsearch indices.recovery 流程分析(索引的_open操作也会触发recovery)——主分片recovery主要是从translog里恢复之前未写完的index,副分片recovery主要是从主分片copy segment和translog来进行恢复

    摘自:https://www.easyice.cn/archives/231 elasticsearch indices.recovery 流程分析与速度优化 目录 [隐藏] 主分片恢复流程 副本分片 ...

  7. 分布式事务之解决方案(TCC)

    4. 分布式事务解决方案之TCC 4.1. 什么是TCC事务 TCC是Try.Confirm.Cancel三个词语的缩写,TCC要求每个分支事务实现三个操作 :预处理Try.确认Confirm.撤销C ...

  8. 分布式事务二TCC

    分布式事务解决方案之TCC 4.1.什么是TCC事务 TCC是Try.Confirm.Cancel三个词语的缩写,TCC要求每个分支事务实现三个操作:预处理Try.确认Confirm.撤销Cancel ...

  9. 分布式事务解决方案汇总:2PC、3PC、消息中间件、TCC、状态机+重试+幂等(转)

    数据一致性问题非常多样,下面举一些常见例子.比如在更新数据的时候,先更新了数据库,后更新了缓存,一旦缓存更新失败,此时数据库和缓存数据会不一致.反过来,如果先更新缓存,再更新数据库,一旦缓存更新成功, ...

随机推荐

  1. 文本分类TextCNN

    参考来源:https://blog.csdn.net/u012762419/article/details/79561441 TextCNN结构 TextCNN的结构比较简单,输入数据首先通过一个em ...

  2. 18-09-21 numpy 的基础学习01

    # 1关于numpy 的学习import numpy as np # 一 如何创建数组****# 1 有规律的一维数据的创建======# 1 range() 和arange() 区别 貌似没有区别l ...

  3. linux下的$0-n作用

    电面的时候回答上来一部分了....呵呵......总结一下!!! $0 Shell本身的文件名 $1-$n 添加到Shell的各参数值.$1是第1参数.$2是第2参数… $$ Shell本身的PID( ...

  4. ArcGIS统计栅格像元值并转换为矢量图层

    很多时候,我们需要得到矢量数据区域所对应栅格数据的像元统计值(求平均.求和等),然后将获得的统计值赋给矢量图层的属性表,在ArcGIS中操作如下:(PS:第一次写技术文章,望大家多多体谅与支持,么么哒 ...

  5. linux 查看当前系统版本号

    为避免现场未能完全安装系统,使用yum 安装版本需一致 第一种方法: [root@sky9896sky]# lsb_release -a bash:lsb_release: command not f ...

  6. emmet简单记录

    一.引式符号 html:5 or  ! . class #  id []标签内属性 pycharm不支持  {}标签的内容 pycharm不支持 ()分组标签  pycharm不支持 二.关系符号 1 ...

  7. shell命令记录

    1. 过滤注释和空行 cat /etc/rsyslog.conf|grep -v "#"  |  grep -v "^$" 2. flume日志采集: for ...

  8. 《CSS揭秘》之毛玻璃效果知识点

    实现代码: CodePen:毛玻璃效果 Dabblet:毛玻璃效果 HTML: <main> <blockquote> <em>"The only way ...

  9. JavaEE思维导图

  10. 1_2_3_4_5 Html-Css

    --------------------------------------------------------------------------------- HTML骨架 <HTML> ...