StartTxTransactionHandler
这里参与者(消费端)自己的事物最后提交需要等待
final Boolean commit = txManagerMessageService.preCommmitTxTransaction(groupId); ---netty阻塞等待 所有参与者的事物正常提交,之后提交自己的事物
整个事物连中有一个事物异常发起者通知这个消息事物的提交回滚--发起者调用参与者
//通知tm整个事务组失败,需要回滚,(回滚那些正常提交的模块,他们正在等待通知。。。。)
txManagerMessageService.rollBackTxTransaction(groupId);
ActorTxTransactionHandler 提供方提交事物
大致的思路都是用了自定义的锁
final BlockTask task = BlockTaskHelper.getInstance().getTask(taskKey);
主线程等待,一个定时线程池轮询协调者状态可以就向下执行,提交---这就是阻塞等待的原理
//线程轮询
transactionThreadPool
.newFixedThreadPool()
.execute(() -> {
final String waitKey = IdWorkerUtils.getInstance().createTaskKey();
final BlockTask waitTask = BlockTaskHelper.getInstance().getTask(waitKey);
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
TransactionStatus transactionStatus = platformTransactionManager.getTransaction(def);
/*
1 设置返回数据res
2 唤醒主线程
3 向TxManager 发送提交整个事务组请求
4 自身进入阻塞,等待TxManager通知是否提交 超时会唤醒 我觉得这里应该是继续提交
5 TxManager 发送提交通知,唤醒线程, 进行提交
6 提交完成后,想txManager 发送事务已经完成的通知
*/
try {
//添加事务组信息
final Boolean success = txManagerMessageService.addTxTransaction(info.getTxGroupId(),
build(waitKey, info));
if (success) {
//发起调用
final Object res = point.proceed();
//设置返回数据,并唤醒之前等待的主线程
task.setAsyncCall(objects -> res);
task.signal();
//调用成功 保存本地补偿信息
String compensateId = txCompensationCommand.saveTxCompensation(info.getInvocation(),
info.getTxGroupId(), waitKey);
/*
*
*等待txManager通知(提交或者回滚) 此线程唤醒(txManager通知客户端,然后唤醒)
* 如果此时TxManager down机或者网络通信异常 需要再开一个调度线程来唤醒
*/
final ScheduledFuture scheduledFuture = transactionThreadPool.multiScheduled(() -> {
LogUtil.info(LOGGER, "事务组id:{},自动超时处理", info::getTxGroupId);
final BlockTask blockTask = BlockTaskHelper.getInstance().getTask(waitKey);
if (!blockTask.isNotify()) {
//如果获取通知超时了,那么就去获取事务组的状态
final int transactionGroupStatus = txManagerMessageService.findTransactionGroupStatus(info.getTxGroupId());
if (TransactionStatusEnum.PRE_COMMIT.getCode() == transactionGroupStatus ||
TransactionStatusEnum.COMMIT.getCode() == transactionGroupStatus) {
//如果事务组是预提交,或者是提交状态
//表明事务组是成功的,这时候就算超时也应该去提交
waitTask.setAsyncCall(objects -> TransactionStatusEnum.COMMIT.getCode());
waitTask.signal();
} else {
LogUtil.info(LOGGER, "事务组id:{},自动超时进行回滚!", info::getTxGroupId);
waitTask.setAsyncCall(objects -> NettyResultEnum.TIME_OUT.getCode());
waitTask.signal();
}
LOGGER.error("============通过定时任务来唤醒线程!事务状态为:{}", transactionGroupStatus);
return true;
} else {
return false;
}
}, info.getWaitMaxTime());
waitTask.await();
LogUtil.info(LOGGER, "已经成功接收txManager指令,并执行!{}",
() -> info.getTxGroupId() + ":" + waitKey);
try {
//如果已经被唤醒,就不需要去执行调度线程了 ,关闭上面的调度线程池中的任务
if (!scheduledFuture.isDone()) {
scheduledFuture.cancel(false);
}
final Integer status = (Integer) waitTask.getAsyncCall().callBack();
if (TransactionStatusEnum.COMMIT.getCode() == status) {
//提交事务
platformTransactionManager.commit(transactionStatus);
//通知tm 自身事务提交
asyncComplete(info.getTxGroupId(), waitKey,
TransactionStatusEnum.COMMIT.getCode(), res);
} else {
//回滚当前事务
platformTransactionManager.rollback(transactionStatus);
//通知tm 自身事务回滚
asyncComplete(info.getTxGroupId(), waitKey,
TransactionStatusEnum.ROLLBACK.getCode(), res);
}
} catch (Throwable throwable) {
platformTransactionManager.rollback(transactionStatus);
throwable.printStackTrace();
} finally {
BlockTaskHelper.getInstance().removeByKey(waitKey);
//删除本地补偿信息
txCompensationCommand.removeTxCompensation(compensateId);
}
} else {
platformTransactionManager.rollback(transactionStatus);
}
} catch (final Throwable throwable) {
throwable.printStackTrace();
//如果有异常 当前项目事务进行回滚
platformTransactionManager.rollback(transactionStatus);
//通知tm 自身事务失败
asyncComplete(info.getTxGroupId(),
waitKey, TransactionStatusEnum.FAILURE.getCode(), throwable.getMessage());
task.setAsyncCall(objects -> {
throw throwable;
});
task.signal();
}
});
//主线程等待
task.await();
回滚(也用消息日志中的信息回滚),提交成功,同时也删除消息事物日志 txCompensationCommand.removeTxCompensation(compensateId);
补偿回滚(也用消息日志中的信息提交)----宕机
//调用成功 保存本地补偿信息
String compensateId = txCompensationCommand.saveTxCompensation(info.getInvocation(),
info.getTxGroupId(), waitKey);
专门有一个线程不断轮询queue中的补偿信息,只要状态对,就执行补偿
StartCompensationHandler:补偿就是哪个事物回滚就去除这个事物消息组中的补偿信息(根据状态)(TxCompensationServiceImpl)
检查补偿队列补偿信息(根据状态)就进入补偿处理器:再一次执行业务代码,提交事物
@Service
public class TxTransactionFactoryServiceImpl implements TxTransactionFactoryService {
@Override
public Class factoryOf(TxTransactionInfo info) throws Throwable {
if (StringUtils.isNoneBlank(info.getCompensationId())) {
return StartCompensationHandler.class;
}
if (StringUtils.isBlank(info.getTxGroupId())) {
return StartTxTransactionHandler.class;
} else {
if (Objects.equals(CommonConstant.COMPENSATE_ID, info.getTxGroupId())) {
return InsideCompensationHandler.class;
}
return ActorTxTransactionHandler.class;
}
}
}
补偿处理器再次处理业务方法,提交一次
final Object proceed = point.proceed();
platformTransactionManager.commit(transactionStatus);
最后删除整个补偿信息
TxTransactionLocal.getInstance().removeTxGroupId();
CompensationLocal.getInstance().removeCompensationId();