hmily tac dubbo demo

This commit is contained in:
yu199195 2020-09-02 20:06:58 +08:00
parent e27fbdee11
commit 37dfce9cc0
14 changed files with 236 additions and 65 deletions

View File

@ -66,15 +66,9 @@ public class HmilyTransactionSelfRecoveryScheduled implements AutoCloseable {
public HmilyTransactionSelfRecoveryScheduled() {
hmilyRepository = ExtensionLoaderFactory.load(HmilyRepository.class, hmilyConfig.getRepository());
this.selfTccRecoveryExecutor =
new ScheduledThreadPoolExecutor(1,
HmilyThreadFactory.create("hmily-tcc-self-recovery", true));
this.selfTacRecoveryExecutor =
new ScheduledThreadPoolExecutor(1,
HmilyThreadFactory.create("hmily-tac-self-recovery", true));
this.cleanHmilyTransactionExecutor =
new ScheduledThreadPoolExecutor(1,
HmilyThreadFactory.create("hmily-transaction-clean", true));
this.selfTccRecoveryExecutor = new ScheduledThreadPoolExecutor(1, HmilyThreadFactory.create("hmily-tcc-self-recovery", true));
this.selfTacRecoveryExecutor = new ScheduledThreadPoolExecutor(1, HmilyThreadFactory.create("hmily-tac-self-recovery", true));
this.cleanHmilyTransactionExecutor = new ScheduledThreadPoolExecutor(1, HmilyThreadFactory.create("hmily-transaction-clean", true));
hmilyTransactionRecoveryService = new HmilyTransactionRecoveryService();
selfTccRecovery();
selfTacRecovery();
@ -85,9 +79,7 @@ public class HmilyTransactionSelfRecoveryScheduled implements AutoCloseable {
private void phyDeleted() {
if (!hmilyConfig.isPhyDeleted()) {
int seconds = hmilyConfig.getStoreDays() * 24 * 60 * 60;
phyDeletedExecutor =
new ScheduledThreadPoolExecutor(1,
HmilyThreadFactory.create("hmily-phyDeleted-clean", true));
phyDeletedExecutor = new ScheduledThreadPoolExecutor(1, HmilyThreadFactory.create("hmily-phyDeleted-clean", true));
phyDeletedExecutor
.scheduleWithFixedDelay(() -> {
try {
@ -127,21 +119,10 @@ public class HmilyTransactionSelfRecoveryScheduled implements AutoCloseable {
LOGGER.info("hmily tcc transaction begin self recovery: {}", hmilyParticipant.toString());
HmilyTransaction globalHmilyTransaction = hmilyRepository.findByTransId(hmilyParticipant.getTransId());
if (Objects.isNull(globalHmilyTransaction)) {
if (hmilyParticipant.getStatus() == HmilyActionEnum.TRYING.getCode()
|| hmilyParticipant.getStatus() == HmilyActionEnum.CANCELING.getCode()) {
hmilyTransactionRecoveryService.cancel(hmilyParticipant);
} else if (hmilyParticipant.getStatus() == HmilyActionEnum.CONFIRMING.getCode()) {
hmilyTransactionRecoveryService.confirm(hmilyParticipant);
}
tccRecovery(hmilyParticipant.getStatus(), hmilyParticipant);
} else {
if (globalHmilyTransaction.getStatus() == HmilyActionEnum.TRYING.getCode()
|| globalHmilyTransaction.getStatus() == HmilyActionEnum.CANCELING.getCode()) {
hmilyTransactionRecoveryService.cancel(hmilyParticipant);
} else if (globalHmilyTransaction.getStatus() == HmilyActionEnum.CONFIRMING.getCode()) {
hmilyTransactionRecoveryService.confirm(hmilyParticipant);
}
tccRecovery(globalHmilyTransaction.getStatus(), hmilyParticipant);
}
}
}
} catch (Exception e) {
@ -150,13 +131,21 @@ public class HmilyTransactionSelfRecoveryScheduled implements AutoCloseable {
}, hmilyConfig.getScheduledInitDelay(), hmilyConfig.getScheduledRecoveryDelay(), TimeUnit.SECONDS);
}
private void tccRecovery(final int status, final HmilyParticipant hmilyParticipant) {
if (status == HmilyActionEnum.TRYING.getCode() || status == HmilyActionEnum.CANCELING.getCode()) {
hmilyTransactionRecoveryService.cancel(hmilyParticipant);
} else if (status == HmilyActionEnum.CONFIRMING.getCode()) {
hmilyTransactionRecoveryService.confirm(hmilyParticipant);
}
}
private void selfTacRecovery() {
selfTacRecoveryExecutor
.scheduleWithFixedDelay(() -> {
try {
List<HmilyParticipant> hmilyParticipantList =
hmilyRepository.listHmilyParticipant(acquireDelayData(hmilyConfig.getRecoverDelayTime()), TransTypeEnum.TAC.name(), hmilyConfig.getLimit());
if (CollectionUtils.isEmpty(hmilyParticipantList)) {
return;
}
@ -170,27 +159,15 @@ public class HmilyTransactionSelfRecoveryScheduled implements AutoCloseable {
final boolean successful = hmilyRepository.lockHmilyParticipant(hmilyParticipant);
// determine that rows > 0 is executed to prevent concurrency when the business side is in cluster mode
if (successful) {
HmilyTransaction globalHmilyTransaction = hmilyRepository.findByTransId(hmilyParticipant.getTransId());
if (Objects.isNull(globalHmilyTransaction)) {
//do remove
hmilyRepository.removeHmilyParticipant(hmilyParticipant.getParticipantId());
}
List<HmilyParticipantUndo> participantUndoList = hmilyRepository.findHmilyParticipantUndoByParticipantId(hmilyParticipant.getParticipantId());
if (CollectionUtils.isEmpty(participantUndoList)) {
continue;
}
if (globalHmilyTransaction.getStatus() == HmilyActionEnum.TRYING.getCode()
|| globalHmilyTransaction.getStatus() == HmilyActionEnum.CANCELING.getCode()) {
for (HmilyParticipantUndo undo : participantUndoList) {
boolean success = UndoHook.INSTANCE.run(undo);
if (success) {
hmilyRepository.removeHmilyParticipantUndo(undo.getUndoId());
}
}
} else if (globalHmilyTransaction.getStatus() == HmilyActionEnum.CONFIRMING.getCode()) {
for (HmilyParticipantUndo undo : participantUndoList) {
hmilyRepository.removeHmilyParticipantUndo(undo.getUndoId());
}
HmilyTransaction globalHmilyTransaction = hmilyRepository.findByTransId(hmilyParticipant.getTransId());
if (Objects.isNull(globalHmilyTransaction)) {
tacRecovery(hmilyParticipant.getStatus(), participantUndoList);
} else {
tacRecovery(globalHmilyTransaction.getStatus(), participantUndoList);
}
}
hmilyRepository.removeHmilyParticipant(hmilyParticipant.getParticipantId());
@ -201,6 +178,21 @@ public class HmilyTransactionSelfRecoveryScheduled implements AutoCloseable {
}, hmilyConfig.getScheduledInitDelay(), hmilyConfig.getScheduledRecoveryDelay(), TimeUnit.SECONDS);
}
private void tacRecovery(final int status, final List<HmilyParticipantUndo> participantUndoList) {
if (status == HmilyActionEnum.TRYING.getCode() || status == HmilyActionEnum.CANCELING.getCode()) {
for (HmilyParticipantUndo undo : participantUndoList) {
boolean success = UndoHook.INSTANCE.run(undo);
if (success) {
hmilyRepository.removeHmilyParticipantUndo(undo.getUndoId());
}
}
} else if (status == HmilyActionEnum.CONFIRMING.getCode()) {
for (HmilyParticipantUndo undo : participantUndoList) {
hmilyRepository.removeHmilyParticipantUndo(undo.getUndoId());
}
}
}
private void cleanHmilyTransaction() {
cleanHmilyTransactionExecutor
.scheduleWithFixedDelay(() -> {

View File

@ -0,0 +1,67 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.hmily.demo.dubbo.account.config;
import com.zaxxer.hikari.HikariDataSource;
import javax.sql.DataSource;
import org.dromara.hmily.tac.p6spy.HmilyP6Datasource;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
/**
* The type Hmily tac datasource config.
*
* @author xiaoyu
*/
@Configuration
public class HmilyTacDatasourceConfig {
private final DataSourceProperties dataSourceProperties;
/**
* Instantiates a new Hmily tac datasource config.
*
* @param dataSourceProperties the data source properties
*/
public HmilyTacDatasourceConfig(DataSourceProperties dataSourceProperties) {
this.dataSourceProperties = dataSourceProperties;
}
/**
* Data source data source.
*
* @return the data source
*/
@Bean
@Primary
public DataSource dataSource() {
HikariDataSource hikariDataSource = new HikariDataSource();
hikariDataSource.setJdbcUrl(dataSourceProperties.getUrl());
hikariDataSource.setDriverClassName(dataSourceProperties.getDriverClassName());
hikariDataSource.setUsername(dataSourceProperties.getUsername());
hikariDataSource.setPassword(dataSourceProperties.getPassword());
hikariDataSource.setMaximumPoolSize(20);
hikariDataSource.setMinimumIdle(10);
hikariDataSource.setConnectionTimeout(30000);
hikariDataSource.setIdleTimeout(600000);
hikariDataSource.setMaxLifetime(1800000);
return new HmilyP6Datasource(hikariDataSource);
}
}

View File

@ -40,6 +40,16 @@ public interface AccountMapper {
" where user_id =#{userId} and balance > 0 ")
int update(AccountDTO accountDTO);
/**
* Update tac int.
*
* @param accountDTO the account dto
* @return the int
*/
@Update("update account set balance = balance - #{amount}, update_time = now()" +
" where user_id =#{userId} and balance > 0 ")
int updateTAC(AccountDTO accountDTO);
/**
* Test update int.
*

View File

@ -109,8 +109,7 @@ public class AccountServiceImpl implements AccountService {
@Override
@HmilyTAC
public boolean paymentTAC(AccountDTO accountDTO) {
accountMapper.update(accountDTO);
return true;
return accountMapper.updateTAC(accountDTO) > 0;
}
@Override

View File

@ -23,7 +23,6 @@ import org.springframework.boot.WebApplicationType;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ImportResource;
/**
* DubboTccInventoryApplication.
*

View File

@ -0,0 +1,67 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.hmily.demo.dubbo.inventory.config;
import com.zaxxer.hikari.HikariDataSource;
import javax.sql.DataSource;
import org.dromara.hmily.tac.p6spy.HmilyP6Datasource;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
/**
* The type Hmily tac datasource config.
*
* @author xiaoyu
*/
@Configuration
public class HmilyTacDatasourceConfig {
private final DataSourceProperties dataSourceProperties;
/**
* Instantiates a new Hmily tac datasource config.
*
* @param dataSourceProperties the data source properties
*/
public HmilyTacDatasourceConfig(DataSourceProperties dataSourceProperties) {
this.dataSourceProperties = dataSourceProperties;
}
/**
* Data source data source.
*
* @return the data source
*/
@Bean
@Primary
public DataSource dataSource() {
HikariDataSource hikariDataSource = new HikariDataSource();
hikariDataSource.setJdbcUrl(dataSourceProperties.getUrl());
hikariDataSource.setDriverClassName(dataSourceProperties.getDriverClassName());
hikariDataSource.setUsername(dataSourceProperties.getUsername());
hikariDataSource.setPassword(dataSourceProperties.getPassword());
hikariDataSource.setMaximumPoolSize(20);
hikariDataSource.setMinimumIdle(10);
hikariDataSource.setConnectionTimeout(30000);
hikariDataSource.setIdleTimeout(600000);
hikariDataSource.setMaxLifetime(1800000);
return new HmilyP6Datasource(hikariDataSource);
}
}

View File

@ -40,6 +40,16 @@ public interface InventoryMapper {
" where product_id =#{productId} and total_inventory > 0 ")
int decrease(InventoryDTO inventoryDTO);
/**
* Decrease tac int.
*
* @param inventoryDTO the inventory dto
* @return the int
*/
@Update("update inventory set total_inventory = total_inventory - #{count} " +
" where product_id =#{productId} and total_inventory > 0 ")
int decreaseTAC(InventoryDTO inventoryDTO);
/**
* Test decrease int.
*

View File

@ -18,6 +18,9 @@
package org.dromara.hmily.demo.dubbo.inventory.service;
import com.google.common.collect.Lists;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import org.dromara.hmily.annotation.HmilyTAC;
import org.dromara.hmily.annotation.HmilyTCC;
import org.dromara.hmily.common.exception.HmilyRuntimeException;
@ -31,10 +34,6 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
/**
* The type Inventory service.
*
@ -72,15 +71,13 @@ public class InventoryServiceImpl implements InventoryService {
@Override
@HmilyTCC(confirmMethod = "confirmMethod", cancelMethod = "cancelMethod")
public Boolean decrease(InventoryDTO inventoryDTO) {
inventoryMapper.decrease(inventoryDTO);
return true;
return inventoryMapper.decrease(inventoryDTO) > 0;
}
@Override
@HmilyTAC
public Boolean decreaseTAC(InventoryDTO inventoryDTO) {
inventoryMapper.decrease(inventoryDTO);
return true;
return inventoryMapper.decreaseTAC(inventoryDTO) > 0;
}
@Override

View File

@ -21,8 +21,8 @@ logging:
root: error
org.springframework.web: info
org.apache.ibatis: debug
org.dromara.hmily.bonuspoint: debug
org.dromara.hmily.lottery: debug
org.dromara.hmily: debug
org.dromara.hmily.demo.bonuspoint: debug
org.dromara.hmily.demo.lottery: debug
org.dromara.hmily.demo: debug
path: "./logs"

View File

@ -25,16 +25,30 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
/**
* The type Hmily tac datasource config.
*
* @author xiaoyu
*/
@Configuration
public class HmilyTacDatasourceConfig {
private final DataSourceProperties dataSourceProperties;
/**
* Instantiates a new Hmily tac datasource config.
*
* @param dataSourceProperties the data source properties
*/
public HmilyTacDatasourceConfig(DataSourceProperties dataSourceProperties) {
this.dataSourceProperties = dataSourceProperties;
}
/**
* Data source data source.
*
* @return the data source
*/
@Bean
@Primary
public DataSource dataSource() {

View File

@ -19,10 +19,10 @@ logging:
level:
root: error
org.springframework.web: info
org.apache.ibatis: info
org.dromara.hmily.bonuspoint: info
org.dromara.hmily.lottery: info
org.dromara.hmily: info
org.apache.ibatis: debug
org.dromara.hmily.demo.bonuspoint: debug
org.dromara.hmily.demo.lottery: debug
org.dromara.hmily.demo: debug
io.netty: info
path: "./logs"

View File

@ -18,11 +18,11 @@
charset="UTF-8" threadpool="fixed" threads="500"
queues="0" buffer="8192" accepts="0" payload="8388608"/>
<dubbo:reference timeout="5000"
<dubbo:reference timeout="500000000"
interface="org.dromara.hmily.demo.dubbo.inventory.api.service.InventoryService"
id="inventoryService"
retries="0" check="false" actives="20" loadbalance="hmilyRandom"/>
<dubbo:reference timeout="5000"
<dubbo:reference timeout="500000000"
interface="org.dromara.hmily.demo.dubbo.account.api.service.AccountService"
id="accountService"
retries="0" check="false" actives="20" loadbalance="hmilyRandom"/>

View File

@ -17,6 +17,7 @@
package org.dromara.hmily.tac.core.transaction;
import com.google.common.collect.Lists;
import java.util.List;
import java.util.Objects;
import org.dromara.hmily.annotation.TransTypeEnum;
@ -25,6 +26,7 @@ import org.dromara.hmily.common.enums.HmilyActionEnum;
import org.dromara.hmily.common.enums.HmilyRoleEnum;
import org.dromara.hmily.common.utils.CollectionUtils;
import org.dromara.hmily.common.utils.IdWorkerUtils;
import org.dromara.hmily.core.cache.HmilyParticipantCacheManager;
import org.dromara.hmily.core.context.HmilyContextHolder;
import org.dromara.hmily.core.context.HmilyTransactionContext;
import org.dromara.hmily.core.holder.HmilyTransactionHolder;
@ -147,6 +149,7 @@ public class HmilyTacStarterTransaction {
if (CollectionUtils.isEmpty(hmilyParticipants)) {
return;
}
List<Boolean> successList = Lists.newArrayList();
for (HmilyParticipant participant : hmilyParticipants) {
try {
if (participant.getRole() == HmilyRoleEnum.START.getCode()) {
@ -156,15 +159,22 @@ public class HmilyTacStarterTransaction {
//clean undo
cleanUndo(undo);
}
cleanHmilyParticipant(participant);
} else {
HmilyReflector.executor(HmilyActionEnum.CONFIRMING, ExecutorTypeEnum.RPC, participant);
}
successList.add(true);
} catch (Throwable e) {
successList.add(false);
LOGGER.error("HmilyParticipant rollback exception :{} ", participant.toString());
} finally {
HmilyContextHolder.remove();
}
}
if (successList.stream().allMatch(e -> e)) {
// remove global
HmilyRepositoryStorage.removeHmilyTransaction(currentTransaction);
}
}
/**
@ -180,6 +190,11 @@ public class HmilyTacStarterTransaction {
HmilyParticipantUndoCacheManager.getInstance().removeByKey(hmilyParticipantUndo.getParticipantId());
}
private void cleanHmilyParticipant(final HmilyParticipant hmilyParticipant) {
HmilyParticipantCacheManager.getInstance().removeByKey(hmilyParticipant.getParticipantId());
HmilyRepositoryStorage.removeHmilyParticipant(hmilyParticipant);
}
/**
* Gets hmily transaction.
*

View File

@ -19,6 +19,7 @@ package org.dromara.hmily.tcc.executor;
import com.google.common.collect.Lists;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import org.aspectj.lang.ProceedingJoinPoint;
@ -130,7 +131,7 @@ public final class HmilyTccTransactionExecutor {
currentTransaction.setStatus(HmilyActionEnum.CONFIRMING.getCode());
HmilyRepositoryStorage.updateHmilyTransactionStatus(currentTransaction);
final List<HmilyParticipant> hmilyParticipants = currentTransaction.getHmilyParticipants();
List<Boolean> successList = Lists.newArrayListWithCapacity(hmilyParticipants.size());
List<Boolean> successList = new ArrayList<>();
for (HmilyParticipant hmilyParticipant : hmilyParticipants) {
try {
if (hmilyParticipant.getRole() == HmilyRoleEnum.START.getCode()) {