TCC细读 - 3 恢复流程
重试定时任务,通过外部调度实现
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 恢复流程的更多相关文章
- TCC细读 - 1 例子流程
http://www.iocoder.cn/categories/TCC-Transaction/ https://github.com/changmingxie/tcc-transaction 细读 ...
- hbase-数据恢复流程
引用<https://blog.csdn.net/nigeaoaojiao/article/details/54909921> hlog介绍: hlog构建: 从图中可以看出,对于一个hl ...
- ASA密码恢复流程
1.建立console连接2.重启启动安全设备 3.进入ROMMMON模式出现Use BREAK or ESC to interrupt boot字样时,按下ESC键进入ROMMON模式.4.设置RO ...
- TCC细读 - 2 核心实现
TCC,基于业务层面的事物定义,粒度完全由业务自己控制,本质上还是补偿的思路,它把事物运行过程分为try-confirm-cancel阶段,每个阶段逻辑由业务代码控制 业务活动管理器控制业务活动的一致 ...
- 基于Redo Log和Undo Log的MySQL崩溃恢复流程
在之前的文章「简单了解InnoDB底层原理」聊了一下MySQL的Buffer Pool.这里再简单提一嘴,Buffer Pool是MySQL内存结构中十分核心的一个组成,你可以先把它想象成一个黑盒子. ...
- elasticsearch indices.recovery 流程分析(索引的_open操作也会触发recovery)——主分片recovery主要是从translog里恢复之前未写完的index,副分片recovery主要是从主分片copy segment和translog来进行恢复
摘自:https://www.easyice.cn/archives/231 elasticsearch indices.recovery 流程分析与速度优化 目录 [隐藏] 主分片恢复流程 副本分片 ...
- 分布式事务之解决方案(TCC)
4. 分布式事务解决方案之TCC 4.1. 什么是TCC事务 TCC是Try.Confirm.Cancel三个词语的缩写,TCC要求每个分支事务实现三个操作 :预处理Try.确认Confirm.撤销C ...
- 分布式事务二TCC
分布式事务解决方案之TCC 4.1.什么是TCC事务 TCC是Try.Confirm.Cancel三个词语的缩写,TCC要求每个分支事务实现三个操作:预处理Try.确认Confirm.撤销Cancel ...
- 分布式事务解决方案汇总:2PC、3PC、消息中间件、TCC、状态机+重试+幂等(转)
数据一致性问题非常多样,下面举一些常见例子.比如在更新数据的时候,先更新了数据库,后更新了缓存,一旦缓存更新失败,此时数据库和缓存数据会不一致.反过来,如果先更新缓存,再更新数据库,一旦缓存更新成功, ...
随机推荐
- webView 获取内容高度不准确的原因是因为你设置了某个属性
不管是UIWebView 还是 WKWebView 这里 获取js属性 获取高度的方法 我就不一一细说了 ,本文最主要不说这个 ,网上有太多的方法 我最不摘几个 CGFloat webViewHeig ...
- 使用CSMA/CD协议一个计算题
题干: 首先计算一下A这个以太网所容许的最短的帧它的发送帧的长度时间为: (8(前同步码为8)+64(最短帧长))*8(单位转换b到B)=576比特 有关于单位转换: B是Byte的缩写,B就是Byt ...
- MySQL常用内置函数
本篇博客源自以下博客地址: http://www.mamicode.com/info-detail-250393.html
- WEBBASE篇: 第六篇, CSS知识4
CSS 1.框模型 1.内边距 属性: padding:value; padding-top / right / bottom / left:value; 2.box-sizing 作用:指定框模型的 ...
- mybatis(一、原理,一对多,多对一查询)
MyBatis框架及原理分析 MyBatis 是支持定制化 SQL.存储过程以及高级映射的优秀的持久层框架,其主要就完成2件事情: 封装JDBC操作 利用反射打通Java类与SQL语句之间的相互转换 ...
- flask自定义转换器
根据具体的需求,有些时候是需要用到正则来灵活匹配URL,但是Flask的路由匹配机制是不能直接在路由里直接写正则的,这时候就需要使用转换器! Flask的默认转换器: DEFAULT_CONVERTE ...
- 本地maven库导入架包
mvn install:install-file -DgroupId=com.alipay -DartifactId=sdk-java -Dversion=20170725114550 -Dpacka ...
- PTA——32位前导零
PTA #include <stdio.h> int main(){ //无符号整型才能表达32位二进制数对应的十进制数 unsigned int decimalNum; unsigned ...
- windows openssh server 安装试用
使用Windows的可能会知道win10 的已经包好了openssh 服务,但是对于其他机器win 7 windows 2008 ,就需要其他的方法了 还好powershell 团队开发了支持wind ...
- shell脚本使用## or %%
今天写脚本的时候,遇到一个文件路径需要去掉右边一部分,当时就想到了这个,但是很久没用过了,很多不记得了,记录一下这种用法 1:vim test.sh #!/bin/bash location=/f ...