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

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. 0913_Python初识及变量

    1.Python3不需加utf-8,Python必须加utf-82.单行注释用#,多行注释用""" """3.变量:只能由字母.数字.下划线 ...

  2. C#手动改变自制窗体的大小

    Form1.cs using System;using System.Collections.Generic;using System.ComponentModel;using System.Data ...

  3. L2-020. 功夫传人*

    L2-020. 功夫传人 参考博客 #include<vector> #include<cstring> #include<algorithm> using nam ...

  4. 网络编程-----IO

    IO模型介绍 阻塞IO 非阻塞 多路复用 异步 IO模型比较分析 selectors 阻塞IO:之前写的所有的socket,recv,accput都是 阻塞原理: 其实多数时间多用到了等待数据那里. ...

  5. Arch Linux root密码忘记了怎么办

    https://wiki.archlinux.org/index.php/Reset_root_password_(简体中文)https://wiki.archlinux.org/index.php/ ...

  6. web-msg-send 学习 http://www.workerman.net/web-sender

    WEB消息推送框架 web-msg-sender是一款web长连接推送框架,采用PHPSocket.IO开发,基于WebSocket长连接通讯,如果浏览器不支持WebSocket则自动转用comet推 ...

  7. ios-UILabel居中随内容自适应,后面的控件跟在其后

    如图绿蓝框所示,UILabel显示名字,Label框随名字长短而自适应,后面的性别图片跟在其后显示 分两部分:第一部分先布局 //名字 self.nameLab = [[UILabel alloc]i ...

  8. SSM框架的配置

    主要是这三个配置文件 web.xml(用来加载和初始化下面的配置文件) applicationcontet.xml(就是Spring的配置文件,一般包括声明式失误等等AOP) Sprimgmvc,xm ...

  9. HttpWebRequest post 请求超时问题

    在使用curl做POST的时候, 当要POST的数据大于1024字节的时候, curl并不会直接就发起POST请求, 而是会分为俩步, 发送一个请求, 包含一个Expect:100-continue, ...

  10. lua tasklib 之lumen 分析

    sched.sleep分析 sleep会填充M.running_task.waitds数据表示当前task需要等待,最后yield出去到主线程 M.sleep = function (timeout) ...