├── .editorconfig ├── .github └── workflows │ └── maven.yml ├── .gitignore ├── LICENSE ├── README.md ├── config └── intellij-java-google-style.xml ├── easy-retry-common ├── pom.xml └── src │ └── main │ └── java │ └── com │ └── alibaba │ └── easyretry │ └── common │ ├── AbstractResultPredicate.java │ ├── AbstractRetrySyncExecutor.java │ ├── EasyRetryPredicate.java │ ├── Invocation.java │ ├── RetryConfiguration.java │ ├── RetryContainer.java │ ├── RetryContext.java │ ├── RetryExecutor.java │ ├── RetryIdentify.java │ ├── RetryLifecycle.java │ ├── RetrySyncExecutor.java │ ├── SCallable.java │ ├── SimpleMethodInvocation.java │ ├── access │ ├── RetrySerializerAccess.java │ ├── RetryStrategyAccess.java │ └── RetryTaskAccess.java │ ├── constant │ ├── enums │ │ ├── HandleResultEnum.java │ │ ├── RetryTaskStatusEnum.java │ │ └── RetryTypeEnum.java │ └── package-info.java │ ├── entity │ └── RetryTask.java │ ├── event │ ├── RetryEvent.java │ ├── RetryEventMulticaster.java │ ├── RetryListener.java │ ├── before │ │ ├── AfterSaveBeforeRetryEvent.java │ │ ├── BeforeRetryEvent.java │ │ └── PrepSaveBeforeRetryEvent.java │ └── on │ │ ├── FailureOnRetryEvent.java │ │ ├── OnRetryEvent.java │ │ ├── StopOnRetryEvent.java │ │ └── SuccessOnRetryEvent.java │ ├── filter │ ├── AbstractRetryFilter.java │ ├── RetryFilter.java │ ├── RetryFilterDiscover.java │ ├── RetryFilterInvocation.java │ ├── RetryFilterInvocationHandler.java │ ├── RetryFilterRegister.java │ ├── RetryFilterRegisterHandler.java │ └── RetryFilterResponse.java │ ├── processor │ ├── AsyncPersistenceProcessor.java │ ├── RetryProcessor.java │ └── SyncProcessor.java │ ├── resolve │ └── ExecutorSolver.java │ ├── retryer │ ├── Retryer.java │ └── RetryerInfo.java │ ├── serializer │ ├── ArgDeSerializerInfo.java │ ├── ArgSerializerInfo.java │ ├── EasyRetrySerializer.java │ ├── ResultPredicateSerializer.java │ └── RetryArgSerializer.java │ └── strategy │ ├── RetryStrategy.java │ ├── StopStrategy.java │ └── WaitStrategy.java ├── easy-retry-core ├── pom.xml └── src │ ├── main │ └── java │ │ └── com │ │ └── alibaba │ │ └── easyretry │ │ └── core │ │ ├── DegradeAbleRetryExecutor.java │ │ ├── PersistenceRetryExecutor.java │ │ ├── PersistenceRetryer.java │ │ ├── PersistenceRetryerBuilder.java │ │ ├── RetryerBuilder.java │ │ ├── SyncRetryer.java │ │ ├── SyncRetryerBuilder.java │ │ ├── access │ │ ├── DefaultRetrySerializerAccess.java │ │ └── MemoryRetryTaskAccess.java │ │ ├── container │ │ └── SimpleRetryContainer.java │ │ ├── context │ │ └── MaxAttemptsPersistenceRetryContext.java │ │ ├── degrade │ │ └── EasyRetryDegradeHelper.java │ │ ├── event │ │ └── SimpleRetryEventMulticaster.java │ │ ├── filter │ │ ├── DefaultRetryFilterInvocationHandler.java │ │ ├── DefaultRetryFilterRegisterHandler.java │ │ ├── IdentifyRetryFilter.java │ │ ├── MethodExcuteRetryFilter.java │ │ ├── NOOPRetryFilter.java │ │ ├── SPIRetryFilterDiscover.java │ │ └── SimpleRetryFilterRegister.java │ │ ├── process │ │ ├── async │ │ │ ├── AbstractAsyncPersistenceProcessor.java │ │ │ ├── before │ │ │ │ ├── AbstractAsyncPersistenceBeforeRetryProcessor.java │ │ │ │ ├── ExceptionPersistenceAsyncBeforeRetryProcessor.java │ │ │ │ └── ResultAsynPersistenceBeforeRetryProcessor.java │ │ │ └── on │ │ │ │ ├── AbstractAsyncPersistenceOnRetryProcessor.java │ │ │ │ ├── ExceptionPersistenceAsynOnRetryProcessor.java │ │ │ │ └── ResultAsynPersistenceOnRetryProcessor.java │ │ └── package-info.java │ │ ├── serializer │ │ ├── FastJsonRetryArgSerializer.java │ │ ├── HessianResultPredicateSerializer.java │ │ └── HessianRetryArgSerializer.java │ │ ├── strategy │ │ └── DefaultRetryStrategy.java │ │ └── utils │ │ ├── HessianSerializerUtils.java │ │ ├── LogUtils.java │ │ └── PrintUtils.java │ └── test │ └── java │ └── com │ └── alibaba │ └── easyretry │ └── core │ └── utils │ └── TestClass.java ├── easy-retry-extensions ├── easy-retry-guava-extension │ ├── pom.xml │ └── src │ │ └── main │ │ └── java │ │ └── com │ │ └── alibaba │ │ └── easyretry │ │ └── extension │ │ └── guava │ │ ├── GuavaRetrySyncExecutor.java │ │ └── package-info.java ├── easy-retry-mybatis-extension │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── alibaba │ │ │ │ └── easyretry │ │ │ │ └── extension │ │ │ │ └── mybatis │ │ │ │ ├── access │ │ │ │ └── MybatisRetryTaskAccess.java │ │ │ │ ├── common │ │ │ │ └── utils │ │ │ │ │ └── HostUtils.java │ │ │ │ ├── dao │ │ │ │ ├── BaseDAOSupport.java │ │ │ │ ├── RetryTaskDAO.java │ │ │ │ └── RetryTaskDAOImpl.java │ │ │ │ ├── po │ │ │ │ └── RetryTaskPO.java │ │ │ │ └── query │ │ │ │ └── RetryTaskQuery.java │ │ └── resources │ │ │ └── dal │ │ │ └── easyretry │ │ │ ├── easy-mybatis-config.xml │ │ │ └── mapper │ │ │ └── easy-retry-task-mapper.xml │ │ └── test │ │ ├── java │ │ └── com │ │ │ └── alibaba │ │ │ └── easyretry │ │ │ └── extension │ │ │ └── mybatis │ │ │ ├── DbConfig.java │ │ │ ├── MyBatisConfig.java │ │ │ ├── access │ │ │ └── MybatisRetryTaskAccessTest.java │ │ │ ├── common │ │ │ └── utils │ │ │ │ └── HostUtilsTest.java │ │ │ └── dao │ │ │ └── RetryTaskDAOImplTest.java │ │ └── resources │ │ ├── logback.xml │ │ └── task.sql ├── easy-retry-spring-extension │ ├── pom.xml │ └── src │ │ └── main │ │ └── java │ │ └── com │ │ └── alibaba │ │ └── easyretry │ │ └── extension │ │ └── spring │ │ ├── RetryListenerInitialize.java │ │ ├── SPELParamPredicate.java │ │ ├── SPELResultPredicate.java │ │ ├── SpringEventApplicationListener.java │ │ ├── SpringRetryFilterDiscover.java │ │ └── aop │ │ ├── EasyRetryable.java │ │ └── RetryInterceptor.java └── pom.xml ├── easy-retry-starters ├── easy-retry-memory-starter │ ├── pom.xml │ └── src │ │ └── main │ │ ├── java │ │ └── com │ │ │ └── alibaba │ │ │ └── easyretry │ │ │ └── memory │ │ │ ├── MemoryAutoConfiguration.java │ │ │ └── config │ │ │ └── EasyRetryMemoryCompatibleProperties.java │ │ └── resources │ │ └── META-INF │ │ ├── additional-spring-configuration-metadata.json │ │ └── spring.factories ├── easy-retry-mybatis-starter │ ├── pom.xml │ └── src │ │ └── main │ │ ├── java │ │ └── com │ │ │ └── alibaba │ │ │ └── easyretry │ │ │ └── mybatis │ │ │ ├── MybatisAutoConfiguration.java │ │ │ └── conifg │ │ │ └── EasyRetryMybatisProperties.java │ │ └── resources │ │ └── META-INF │ │ ├── additional-spring-configuration-metadata.json │ │ └── spring.factories ├── easy-retry-starter-common │ ├── pom.xml │ └── src │ │ └── main │ │ └── java │ │ └── com │ │ └── alibaba │ │ └── easyretry │ │ └── starter │ │ └── common │ │ └── CommonAutoConfiguration.java └── pom.xml ├── img └── readme │ └── arch.jpg └── pom.xml /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | 6 | [*.java] 7 | indent_style = tab 8 | indent_size = 4 9 | end_of_line = lf 10 | trim_trailing_whitespace = true 11 | insert_final_newline = true 12 | 13 | [*.{json, yml, xml}] 14 | indent_style = tab 15 | indent_size = 4 16 | 17 | [*.md] 18 | insert_final_newline = false 19 | trim_trailing_whitespace = false 20 | 21 | [*.properties] 22 | ij_properties_align_group_field_declarations = false 23 | ij_properties_keep_blank_lines = false 24 | ij_properties_key_value_delimiter = equals 25 | ij_properties_spaces_around_key_value_delimiter = false -------------------------------------------------------------------------------- /.github/workflows/maven.yml: -------------------------------------------------------------------------------- 1 | # This workflow will build a Java project with Maven 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven 3 | 4 | name: Java CI with Maven 5 | 6 | on: 7 | push: 8 | branches: [ main ] 9 | pull_request: 10 | branches: [ main ] 11 | 12 | 13 | jobs: 14 | build: 15 | runs-on: ubuntu-latest 16 | steps: 17 | - uses: actions/checkout@v2 18 | - name: Set up JDK 1.8 19 | uses: actions/setup-java@v1 20 | with: 21 | java-version: 1.8 22 | - name: Build with Maven 23 | run: mvn -B package --file pom.xml 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | *.class 3 | *.classpath 4 | *.factorypath 5 | 6 | # Log file 7 | *.log 8 | 9 | # BlueJ files 10 | *.ctxt 11 | 12 | # Mobile Tools for Java (J2ME) 13 | .mtj.tmp/ 14 | 15 | # Package Files # 16 | *.jar 17 | *.war 18 | *.ear 19 | *.zip 20 | *.tar.gz 21 | *.rar 22 | 23 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 24 | hs_err_pid* 25 | 26 | # IDE Files # 27 | *.iml 28 | .idea 29 | .idea/ 30 | .project 31 | .settings 32 | target 33 | .DS_Store 34 | 35 | # temp ignore 36 | *.cache 37 | *.diff 38 | *.patch 39 | *.tmp 40 | 41 | # Maven ignore 42 | .flattened-pom.xml 43 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Alibaba 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Easy-Retry 2 | 3 | 一种存储介质可扩展的持久化重试方案 4 | ![img](img/readme/arch.jpg) 5 | 6 | ### Getting started 7 | 8 | #### Memory Retry 9 | 10 | 1. 增加pom依赖 11 | 12 | ```xml 13 | 14 | com.alibaba 15 | easy-retry-memory-starter 16 | ${last-version} 17 | 18 | ``` 19 | 20 | 2. 在application.properties增加配置 21 | 22 | `spring.easyretry.memory.enabled = true` 23 | 24 | 3. 在需要重试的方法上增加`@EasyRetryable`注解 25 | 26 | ```java 27 | public class MemoryUserService { 28 | @EasyRetryable 29 | public User getUserById(Long userId){ 30 | return new User(); 31 | } 32 | } 33 | ``` 34 | 35 | #### Mybatis Retry 36 | 37 | 1. 增加pom依赖 38 | ```xml 39 | 40 | com.alibaba 41 | easy-retry-mybatis-starter 42 | ${last-version} 43 | 44 | ``` 45 | 46 | 2. 在application.properties增加配置 47 | 48 | `spring.easyretry.mybatis.enabled = true` 49 | 50 | 3. 声明`javax.sql.DataSource`的`Bean`实例,参考下面例子(以`druid`连接池为例) 51 | ``` 52 | @Bean(name = "easyRetryMybatisDataSource", initMethod = "init", destroyMethod = "close") 53 | public DataSource easyRetryMybatisDataSource() { 54 | DruidDataSource tds = new DruidDataSource(); 55 | tds.setUrl(""); 56 | tds.setUsername(""); 57 | tds.setPassword(""); 58 | ... 59 | return tds; 60 | } 61 | ``` 62 | 63 | 4. 新增持久化表 64 | 65 | ``` 66 | CREATE TABLE `easy_retry_task` ( 67 | `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', 68 | `gmt_create` datetime NOT NULL COMMENT '创建时间', 69 | `gmt_modified` datetime NOT NULL COMMENT '修改时间', 70 | `sharding` varchar(64) DEFAULT NULL COMMENT '数据库分片字段', 71 | `biz_id` varchar(64) DEFAULT NULL COMMENT '业务id', 72 | `executor_name` varchar(512) NOT NULL COMMENT '执行名称', 73 | `executor_method_name` varchar(512) NOT NULL COMMENT '执行方法名称', 74 | `retry_status` tinyint(4) NOT NULL COMMENT '重试状态', 75 | `args_str` varchar(7168) DEFAULT NULL COMMENT '执行方法参数', 76 | `ext_attrs` varchar(3000) DEFAULT NULL COMMENT '扩展字段', 77 | PRIMARY KEY (`id`) 78 | ) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8 COMMENT='easy_retry_task' 79 | ; 80 | ``` 81 | 82 | 5. 在需要重试的方法上增加@EasyRetryable注解 83 | 84 | ```java 85 | public class MybatisUserService { 86 | @EasyRetryable 87 | public User getUserById(Long userId){ 88 | return new User(); 89 | } 90 | } 91 | ``` 92 | 93 | ### Built With 94 | 95 | • JDK1.8 96 | 97 | • Spring Framework5+ 98 | 99 | • Spring Boot2.4+ 100 | 101 | • Maven3.0 102 | -------------------------------------------------------------------------------- /config/intellij-java-google-style.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 15 | 21 | 28 | -------------------------------------------------------------------------------- /easy-retry-common/pom.xml: -------------------------------------------------------------------------------- 1 | 4 | 4.0.0 5 | 6 | com.alibaba 7 | easy-retry 8 | ${revision} 9 | ../pom.xml 10 | 11 | easy-retry-common 12 | easy-retry-common 13 | easy-retry-common 14 | 15 | 16 | 17 | org.projectlombok 18 | lombok 19 | 20 | 21 | org.apache.commons 22 | commons-lang3 23 | 24 | 25 | com.google.guava 26 | guava 27 | 28 | 29 | org.slf4j 30 | slf4j-api 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /easy-retry-common/src/main/java/com/alibaba/easyretry/common/AbstractResultPredicate.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.common; 2 | 3 | /** 4 | * @author Created by wuhao on 2021/3/26. 5 | */ 6 | public abstract class AbstractResultPredicate implements EasyRetryPredicate { 7 | 8 | @Override 9 | public abstract Boolean apply(T result); 10 | 11 | } 12 | -------------------------------------------------------------------------------- /easy-retry-common/src/main/java/com/alibaba/easyretry/common/AbstractRetrySyncExecutor.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.common; 2 | 3 | import com.alibaba.easyretry.common.retryer.RetryerInfo; 4 | 5 | /** 6 | * @author zhangchi20 7 | * Created on 2023-07-17 8 | */ 9 | public abstract class AbstractRetrySyncExecutor implements RetrySyncExecutor { 10 | 11 | private RetryerInfo retryerInfo; 12 | 13 | @Override 14 | public void setRetryerInfo(RetryerInfo retryerInfo) { 15 | this.retryerInfo = retryerInfo; 16 | } 17 | 18 | public RetryerInfo getRetryerInfo() { 19 | return retryerInfo; 20 | } 21 | 22 | 23 | @Override 24 | public abstract V call(SCallable callable) throws Throwable; 25 | 26 | } 27 | -------------------------------------------------------------------------------- /easy-retry-common/src/main/java/com/alibaba/easyretry/common/EasyRetryPredicate.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.common; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * @author Created by wuhao on 2021/3/18. 7 | */ 8 | public interface EasyRetryPredicate extends Serializable { 9 | 10 | R apply(T result); 11 | 12 | } 13 | -------------------------------------------------------------------------------- /easy-retry-common/src/main/java/com/alibaba/easyretry/common/Invocation.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.common; 2 | 3 | /** 4 | * @author Created by wuhao on 2021/3/29. 5 | */ 6 | public interface Invocation { 7 | 8 | Object invoke() throws Throwable; 9 | 10 | } 11 | -------------------------------------------------------------------------------- /easy-retry-common/src/main/java/com/alibaba/easyretry/common/RetryConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.common; 2 | 3 | import com.alibaba.easyretry.common.access.RetrySerializerAccess; 4 | import com.alibaba.easyretry.common.access.RetryStrategyAccess; 5 | import com.alibaba.easyretry.common.access.RetryTaskAccess; 6 | import com.alibaba.easyretry.common.event.RetryEventMulticaster; 7 | import com.alibaba.easyretry.common.resolve.ExecutorSolver; 8 | import com.alibaba.easyretry.common.serializer.ResultPredicateSerializer; 9 | 10 | /** 11 | * @author Created by wuhao on 2020/11/5. 12 | */ 13 | public interface RetryConfiguration { 14 | 15 | RetryTaskAccess getRetryTaskAccess(); 16 | 17 | RetrySerializerAccess getRetrySerializerAccess(); 18 | 19 | RetryStrategyAccess getRetryStrategyAccess(); 20 | 21 | ExecutorSolver getExecutorSolver(); 22 | 23 | ResultPredicateSerializer getResultPredicateSerializer(); 24 | 25 | Integer getMaxRetryTimes(); 26 | 27 | RetryEventMulticaster getRetryEventMulticaster(); 28 | 29 | default AbstractRetrySyncExecutor getRetrySyncExecutor() { 30 | return null; 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /easy-retry-common/src/main/java/com/alibaba/easyretry/common/RetryContainer.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.common; 2 | 3 | /** 4 | * @author Created by wuhao on 2020/11/5. 5 | */ 6 | public interface RetryContainer extends RetryLifecycle { 7 | 8 | } 9 | -------------------------------------------------------------------------------- /easy-retry-common/src/main/java/com/alibaba/easyretry/common/RetryContext.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.common; 2 | 3 | public interface RetryContext extends RetryLifecycle { 4 | 5 | void setAttribute(String key, String value); 6 | 7 | String getAttribute(String key); 8 | 9 | /** 10 | * 获取唯一标识 11 | */ 12 | String getId(); 13 | 14 | Invocation getInvocation(); 15 | 16 | } 17 | -------------------------------------------------------------------------------- /easy-retry-common/src/main/java/com/alibaba/easyretry/common/RetryExecutor.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.common; 2 | 3 | import com.alibaba.easyretry.common.constant.enums.HandleResultEnum; 4 | 5 | /** 6 | * @author Created by wuhao on 2021/3/2. 7 | */ 8 | public interface RetryExecutor { 9 | 10 | HandleResultEnum doExecute(RetryContext context); 11 | } 12 | -------------------------------------------------------------------------------- /easy-retry-common/src/main/java/com/alibaba/easyretry/common/RetryIdentify.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.common; 2 | 3 | import java.util.Objects; 4 | 5 | /** 6 | * @author Created by wuhao on 2021/2/20. 7 | */ 8 | public class RetryIdentify { 9 | 10 | private static final ThreadLocal RETRY_CONTEXT_THREAD_LOCAL = new ThreadLocal<>(); 11 | 12 | private static final String RETRY_FLAG = "RETRY_FLAG"; 13 | 14 | public static void start() { 15 | RETRY_CONTEXT_THREAD_LOCAL.set(RETRY_FLAG); 16 | } 17 | 18 | public static void stop() { 19 | RETRY_CONTEXT_THREAD_LOCAL.set(null); 20 | } 21 | 22 | public static boolean isOnRetry() { 23 | return Objects.nonNull(RETRY_CONTEXT_THREAD_LOCAL.get()); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /easy-retry-common/src/main/java/com/alibaba/easyretry/common/RetryLifecycle.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.common; 2 | 3 | /** 4 | * @author Created by wuhao on 2020/11/2. 5 | */ 6 | public interface RetryLifecycle { 7 | 8 | void start(); 9 | 10 | void stop(); 11 | } 12 | -------------------------------------------------------------------------------- /easy-retry-common/src/main/java/com/alibaba/easyretry/common/RetrySyncExecutor.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.common; 2 | 3 | import com.alibaba.easyretry.common.retryer.RetryerInfo; 4 | 5 | /** 6 | * @author zhangchi20 7 | * Created on 2023-07-17 8 | */ 9 | public interface RetrySyncExecutor { 10 | 11 | V call(SCallable callable) throws Throwable; 12 | 13 | void setRetryerInfo(RetryerInfo retryerInfo); 14 | 15 | } 16 | -------------------------------------------------------------------------------- /easy-retry-common/src/main/java/com/alibaba/easyretry/common/SCallable.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.common; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * @author Created by wuhao on 2020/11/5. 7 | */ 8 | @FunctionalInterface 9 | public interface SCallable extends Serializable { 10 | 11 | V call() throws Throwable; 12 | } 13 | -------------------------------------------------------------------------------- /easy-retry-common/src/main/java/com/alibaba/easyretry/common/SimpleMethodInvocation.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.common; 2 | 3 | import java.lang.reflect.Method; 4 | import java.util.Arrays; 5 | 6 | import lombok.AllArgsConstructor; 7 | import lombok.Setter; 8 | 9 | /** 10 | * @author Created by wuhao on 2021/3/29. 11 | */ 12 | @AllArgsConstructor 13 | public class SimpleMethodInvocation implements Invocation { 14 | 15 | @Setter 16 | private Object executor; 17 | 18 | @Setter 19 | private Method method; 20 | 21 | @Setter 22 | private Object[] args; 23 | 24 | @Override 25 | public Object invoke() throws Throwable { 26 | return method.invoke(executor, args); 27 | } 28 | 29 | @Override 30 | public String toString() { 31 | return "[Invocation] executor is " + executor.getClass().getName() + " method is " + method 32 | .getName() + " args is " + Arrays.toString(args); 33 | 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /easy-retry-common/src/main/java/com/alibaba/easyretry/common/access/RetrySerializerAccess.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.common.access; 2 | 3 | import com.alibaba.easyretry.common.serializer.RetryArgSerializer; 4 | 5 | /** 6 | * 重试信息序列化器获取 如果方法上有指定序列化器,则使用getRetrySerializer 否则使用全局序列化器getCurrentGlobalRetrySerializer 7 | * 8 | * @author Created by wuhao on 2020/11/6. 9 | */ 10 | public interface RetrySerializerAccess { 11 | 12 | /** 13 | * 获取全局序列化器 14 | */ 15 | RetryArgSerializer getCurrentGlobalRetrySerializer(); 16 | 17 | } 18 | -------------------------------------------------------------------------------- /easy-retry-common/src/main/java/com/alibaba/easyretry/common/access/RetryStrategyAccess.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.common.access; 2 | 3 | import com.alibaba.easyretry.common.strategy.StopStrategy; 4 | import com.alibaba.easyretry.common.strategy.WaitStrategy; 5 | 6 | /** 7 | * 重试策略获取 如果方法上有指定则用指定Strategy 否则使用Global 8 | * 9 | * @author Created by wuhao on 2020/11/6. 10 | */ 11 | public interface RetryStrategyAccess { 12 | 13 | /** 14 | * 获取全局重试任务停止策略 15 | */ 16 | StopStrategy getCurrentGlobalStopStrategy(); 17 | 18 | /** 19 | * 获取全局等待策略 20 | */ 21 | WaitStrategy getCurrentGlobalWaitStrategy(); 22 | 23 | } 24 | -------------------------------------------------------------------------------- /easy-retry-common/src/main/java/com/alibaba/easyretry/common/access/RetryTaskAccess.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.common.access; 2 | 3 | import java.util.List; 4 | 5 | import com.alibaba.easyretry.common.entity.RetryTask; 6 | 7 | /** 8 | * 重试任务获取器 9 | */ 10 | public interface RetryTaskAccess { 11 | 12 | /** 13 | * 保存重试任务 14 | */ 15 | boolean saveRetryTask(RetryTask retryTask); 16 | 17 | /** 18 | * 更改重试任务为处理中 19 | */ 20 | boolean handlingRetryTask(RetryTask retryTask); 21 | 22 | /** 23 | * 完结重试任务 24 | */ 25 | boolean finishRetryTask(RetryTask retryTask); 26 | 27 | /** 28 | * 停止重试任务 29 | */ 30 | boolean stopRetryTask(RetryTask retryTask); 31 | 32 | /** 33 | * 批量查询重试任务 34 | */ 35 | List listAvailableTasks(Long lastId); 36 | } 37 | -------------------------------------------------------------------------------- /easy-retry-common/src/main/java/com/alibaba/easyretry/common/constant/enums/HandleResultEnum.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.common.constant.enums; 2 | 3 | /** 4 | * 重试任务重试结果 5 | * 6 | * @author Created by wuhao on 2020/11/1. 7 | */ 8 | public enum HandleResultEnum { 9 | 10 | /** 11 | * 处理成功 12 | */ 13 | SUCCESS, 14 | 15 | /** 16 | * 处理失败 17 | */ 18 | FAILURE, 19 | 20 | /** 21 | * 等待策略返回该case还在等待队列中 22 | */ 23 | WAITING, 24 | 25 | /** 26 | * 根据停止策略该笔case停止重试 27 | */ 28 | STOP, 29 | 30 | ERROR; 31 | } 32 | -------------------------------------------------------------------------------- /easy-retry-common/src/main/java/com/alibaba/easyretry/common/constant/enums/RetryTaskStatusEnum.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.common.constant.enums; 2 | 3 | import java.util.Map; 4 | import java.util.stream.Collectors; 5 | import java.util.stream.Stream; 6 | 7 | import lombok.Getter; 8 | 9 | /** 10 | * 重试任务状态 11 | * 12 | * @author Created by wuhao on 2020/10/31. 13 | */ 14 | public enum RetryTaskStatusEnum { 15 | 16 | /** 17 | * 初始化状态 18 | */ 19 | INIT(0, "初始化"), 20 | 21 | /** 22 | * 任务处理中 23 | */ 24 | HANDLING(1, "处理中"), 25 | 26 | /** 27 | * 任务处理异常 28 | */ 29 | ERROR(2, "异常"), 30 | 31 | /** 32 | * 任务完结 33 | */ 34 | FINISH(3, "完结"); 35 | 36 | private static final Map MAP = 37 | Stream.of(values()) 38 | .collect(Collectors.toMap(RetryTaskStatusEnum::getCode, (value) -> value)); 39 | @Getter 40 | private int code; 41 | @Getter 42 | private String desc; 43 | 44 | RetryTaskStatusEnum(int code, String desc) { 45 | this.code = code; 46 | this.desc = desc; 47 | } 48 | 49 | public static RetryTaskStatusEnum fromCode(int code) { 50 | return MAP.get(code); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /easy-retry-common/src/main/java/com/alibaba/easyretry/common/constant/enums/RetryTypeEnum.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.common.constant.enums; 2 | 3 | /** 4 | * 重试种类 5 | * 6 | * @author Created by zhangchi on 2023-07-12 7 | */ 8 | public enum RetryTypeEnum { 9 | 10 | /** 11 | * 同步 12 | */ 13 | SYNC, 14 | 15 | /** 16 | * 异步 17 | */ 18 | ASYNC, 19 | ; 20 | 21 | } 22 | -------------------------------------------------------------------------------- /easy-retry-common/src/main/java/com/alibaba/easyretry/common/constant/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Created by wuhao on 2020/11/6. 3 | */ 4 | package com.alibaba.easyretry.common.constant; 5 | -------------------------------------------------------------------------------- /easy-retry-common/src/main/java/com/alibaba/easyretry/common/entity/RetryTask.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.common.entity; 2 | 3 | import java.util.Date; 4 | import java.util.Map; 5 | 6 | import com.alibaba.easyretry.common.constant.enums.RetryTaskStatusEnum; 7 | 8 | import lombok.Data; 9 | 10 | /** 11 | * 重试任务实体 12 | * 13 | * @author wuhao 14 | */ 15 | @Data 16 | public class RetryTask { 17 | 18 | /** 19 | * 主键id 20 | */ 21 | private Long id; 22 | 23 | /** 24 | * 业务信息 25 | */ 26 | private String bizId; 27 | 28 | /** 29 | * 执行者名称 30 | */ 31 | private String executorName; 32 | 33 | /** 34 | * 执行者方法 35 | */ 36 | private String executorMethodName; 37 | 38 | /** 39 | * 当重试失败时候执行的方法 40 | */ 41 | private String onFailureMethod; 42 | 43 | /** 44 | * 重试任务状态 45 | */ 46 | private RetryTaskStatusEnum status; 47 | 48 | /** 49 | * 任务上的扩展字段 50 | */ 51 | private Map extAttrs; 52 | 53 | /** 54 | * 重试执行者方法参数 55 | */ 56 | private String argsStr; 57 | 58 | private Date gmtCreate; 59 | 60 | private Date gmtModified; 61 | } 62 | -------------------------------------------------------------------------------- /easy-retry-common/src/main/java/com/alibaba/easyretry/common/event/RetryEvent.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.common.event; 2 | 3 | /** 4 | * @author Created by wuhao on 2021/3/25. 5 | */ 6 | public interface RetryEvent { 7 | 8 | String getName(); 9 | 10 | boolean isOnRetry(); 11 | 12 | void setAttribute(String key, String vule); 13 | } 14 | -------------------------------------------------------------------------------- /easy-retry-common/src/main/java/com/alibaba/easyretry/common/event/RetryEventMulticaster.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.common.event; 2 | 3 | /** 4 | * @author Created by wuhao on 2021/3/26. 5 | */ 6 | public interface RetryEventMulticaster { 7 | 8 | void register(RetryListener listener); 9 | 10 | void multicast(RetryEvent retryEvent); 11 | 12 | } 13 | -------------------------------------------------------------------------------- /easy-retry-common/src/main/java/com/alibaba/easyretry/common/event/RetryListener.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.common.event; 2 | 3 | /** 4 | * @author Created by wuhao on 2021/3/25. 5 | */ 6 | public interface RetryListener { 7 | 8 | void onRetryEvent(T event); 9 | 10 | } 11 | -------------------------------------------------------------------------------- /easy-retry-common/src/main/java/com/alibaba/easyretry/common/event/before/AfterSaveBeforeRetryEvent.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.common.event.before; 2 | 3 | import com.alibaba.easyretry.common.entity.RetryTask; 4 | 5 | /** 6 | * @author Created by wuhao on 2021/3/25. 7 | */ 8 | public class AfterSaveBeforeRetryEvent extends BeforeRetryEvent { 9 | 10 | public AfterSaveBeforeRetryEvent(RetryTask retryTask) { 11 | super(retryTask); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /easy-retry-common/src/main/java/com/alibaba/easyretry/common/event/before/BeforeRetryEvent.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.common.event.before; 2 | 3 | import java.util.Map; 4 | import java.util.Objects; 5 | 6 | import com.alibaba.easyretry.common.entity.RetryTask; 7 | import com.alibaba.easyretry.common.event.RetryEvent; 8 | 9 | import com.google.common.collect.Maps; 10 | 11 | /** 12 | * @author Created by wuhao on 2021/3/25. 13 | */ 14 | public abstract class BeforeRetryEvent implements RetryEvent { 15 | 16 | private RetryTask retryTask; 17 | 18 | public BeforeRetryEvent(RetryTask retryTask) { 19 | this.retryTask = retryTask; 20 | } 21 | 22 | @Override 23 | public boolean isOnRetry() { 24 | return false; 25 | } 26 | 27 | @Override 28 | public void setAttribute(String key, String value) { 29 | Map extAttrs = retryTask.getExtAttrs(); 30 | if (Objects.isNull(extAttrs)) { 31 | extAttrs = Maps.newHashMap(); 32 | } 33 | extAttrs.put(key, value); 34 | } 35 | 36 | @Override 37 | public String getName() { 38 | return this.getClass().getSimpleName(); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /easy-retry-common/src/main/java/com/alibaba/easyretry/common/event/before/PrepSaveBeforeRetryEvent.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.common.event.before; 2 | 3 | import com.alibaba.easyretry.common.entity.RetryTask; 4 | 5 | /** 6 | * @author Created by wuhao on 2021/3/25. 7 | */ 8 | public class PrepSaveBeforeRetryEvent extends BeforeRetryEvent { 9 | 10 | public PrepSaveBeforeRetryEvent(RetryTask retryTask) { 11 | super(retryTask); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /easy-retry-common/src/main/java/com/alibaba/easyretry/common/event/on/FailureOnRetryEvent.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.common.event.on; 2 | 3 | import com.alibaba.easyretry.common.RetryContext; 4 | 5 | /** 6 | * @author Created by wuhao on 2021/3/25. 7 | */ 8 | public class FailureOnRetryEvent extends OnRetryEvent { 9 | 10 | public FailureOnRetryEvent(RetryContext retryContext) { 11 | super(retryContext); 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /easy-retry-common/src/main/java/com/alibaba/easyretry/common/event/on/OnRetryEvent.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.common.event.on; 2 | 3 | import com.alibaba.easyretry.common.RetryContext; 4 | import com.alibaba.easyretry.common.event.RetryEvent; 5 | 6 | /** 7 | * @author Created by wuhao on 2021/3/25. 8 | */ 9 | public abstract class OnRetryEvent implements RetryEvent { 10 | 11 | final private RetryContext retryContext; 12 | 13 | public OnRetryEvent(RetryContext retryContext) { 14 | this.retryContext = retryContext; 15 | } 16 | 17 | @Override 18 | public void setAttribute(String key, String value) { 19 | retryContext.setAttribute(key, value); 20 | } 21 | 22 | public String getAttribute(String key) { 23 | return retryContext.getAttribute(key); 24 | } 25 | 26 | @Override 27 | public boolean isOnRetry() { 28 | return true; 29 | } 30 | 31 | @Override 32 | public String getName() { 33 | return this.getClass().getSimpleName(); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /easy-retry-common/src/main/java/com/alibaba/easyretry/common/event/on/StopOnRetryEvent.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.common.event.on; 2 | 3 | import com.alibaba.easyretry.common.RetryContext; 4 | 5 | /** 6 | * @author Created by wuhao on 2021/3/25. 7 | */ 8 | public class StopOnRetryEvent extends OnRetryEvent { 9 | 10 | public StopOnRetryEvent(RetryContext retryContext) { 11 | super(retryContext); 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /easy-retry-common/src/main/java/com/alibaba/easyretry/common/event/on/SuccessOnRetryEvent.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.common.event.on; 2 | 3 | import com.alibaba.easyretry.common.RetryContext; 4 | 5 | /** 6 | * @author Created by wuhao on 2021/3/25. 7 | */ 8 | public class SuccessOnRetryEvent extends OnRetryEvent { 9 | 10 | public SuccessOnRetryEvent(RetryContext retryContext) { 11 | super(retryContext); 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /easy-retry-common/src/main/java/com/alibaba/easyretry/common/filter/AbstractRetryFilter.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.common.filter; 2 | 3 | /** 4 | * @author Created by wuhao on 2021/3/22. 5 | */ 6 | public abstract class AbstractRetryFilter implements RetryFilter { 7 | 8 | protected RetryFilter next; 9 | 10 | @Override 11 | public void setNext(RetryFilter next) { 12 | this.next = next; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /easy-retry-common/src/main/java/com/alibaba/easyretry/common/filter/RetryFilter.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.common.filter; 2 | 3 | import com.alibaba.easyretry.common.RetryContext; 4 | 5 | /** 6 | * @author Created by wuhao on 2021/3/22. 7 | */ 8 | public interface RetryFilter { 9 | 10 | RetryFilterResponse doFilter(RetryContext retryContext) throws Throwable; 11 | 12 | void setNext(RetryFilter next); 13 | 14 | } 15 | -------------------------------------------------------------------------------- /easy-retry-common/src/main/java/com/alibaba/easyretry/common/filter/RetryFilterDiscover.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.common.filter; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * @author Created by wuhao on 2021/4/9. 7 | */ 8 | public interface RetryFilterDiscover { 9 | 10 | List discoverAll(); 11 | } 12 | -------------------------------------------------------------------------------- /easy-retry-common/src/main/java/com/alibaba/easyretry/common/filter/RetryFilterInvocation.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.common.filter; 2 | 3 | import com.alibaba.easyretry.common.RetryContext; 4 | 5 | /** 6 | * @author Created by wuhao on 2021/4/10. 7 | */ 8 | public interface RetryFilterInvocation { 9 | 10 | RetryFilterResponse invoke(RetryContext retryContext) throws Throwable; 11 | 12 | } 13 | -------------------------------------------------------------------------------- /easy-retry-common/src/main/java/com/alibaba/easyretry/common/filter/RetryFilterInvocationHandler.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.common.filter; 2 | 3 | /** 4 | * @author Created by wuhao on 2021/3/19. 5 | */ 6 | public interface RetryFilterInvocationHandler { 7 | void handle(); 8 | 9 | } 10 | -------------------------------------------------------------------------------- /easy-retry-common/src/main/java/com/alibaba/easyretry/common/filter/RetryFilterRegister.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.common.filter; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * @author Created by wuhao on 2021/3/22. 7 | */ 8 | public interface RetryFilterRegister { 9 | 10 | void register(RetryFilter retryFilter); 11 | 12 | List export(); 13 | 14 | } 15 | -------------------------------------------------------------------------------- /easy-retry-common/src/main/java/com/alibaba/easyretry/common/filter/RetryFilterRegisterHandler.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.common.filter; 2 | 3 | /** 4 | * @author Created by wuhao on 2021/4/9. 5 | */ 6 | public interface RetryFilterRegisterHandler { 7 | 8 | void handle(); 9 | 10 | } 11 | -------------------------------------------------------------------------------- /easy-retry-common/src/main/java/com/alibaba/easyretry/common/filter/RetryFilterResponse.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.common.filter; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * @author Created by wuhao on 2021/3/22. 7 | */ 8 | @Data 9 | public class RetryFilterResponse { 10 | 11 | private Object response; 12 | 13 | } 14 | -------------------------------------------------------------------------------- /easy-retry-common/src/main/java/com/alibaba/easyretry/common/processor/AsyncPersistenceProcessor.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.common.processor; 2 | 3 | /** 4 | * @author Created by wuhao on 2021/3/19. 5 | */ 6 | public interface AsyncPersistenceProcessor extends RetryProcessor { 7 | 8 | @Override 9 | void process(); 10 | 11 | boolean needRetry(); 12 | 13 | R getResult() throws Throwable; 14 | 15 | } 16 | -------------------------------------------------------------------------------- /easy-retry-common/src/main/java/com/alibaba/easyretry/common/processor/RetryProcessor.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.common.processor; 2 | 3 | /** 4 | * @author Created by wuhao on 2021/3/19. 5 | */ 6 | public interface RetryProcessor { 7 | 8 | void process(); 9 | 10 | } 11 | -------------------------------------------------------------------------------- /easy-retry-common/src/main/java/com/alibaba/easyretry/common/processor/SyncProcessor.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.common.processor; 2 | 3 | /** 4 | * @author Created by zhangchi on 2023-07-12 5 | */ 6 | public interface SyncProcessor extends RetryProcessor { 7 | 8 | R getResult() throws Throwable; 9 | 10 | } 11 | -------------------------------------------------------------------------------- /easy-retry-common/src/main/java/com/alibaba/easyretry/common/resolve/ExecutorSolver.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.common.resolve; 2 | 3 | /** 4 | * @author Created by wuhao on 2020/11/8. 5 | */ 6 | public interface ExecutorSolver { 7 | 8 | Object resolver(String executorName); 9 | } 10 | -------------------------------------------------------------------------------- /easy-retry-common/src/main/java/com/alibaba/easyretry/common/retryer/Retryer.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.common.retryer; 2 | 3 | import com.alibaba.easyretry.common.SCallable; 4 | 5 | /** 6 | * @author Created by wuhao on 2020/11/5. 7 | */ 8 | public interface Retryer { 9 | 10 | V call(SCallable callable) throws Throwable; 11 | 12 | } 13 | -------------------------------------------------------------------------------- /easy-retry-common/src/main/java/com/alibaba/easyretry/common/retryer/RetryerInfo.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.common.retryer; 2 | 3 | import com.alibaba.easyretry.common.AbstractResultPredicate; 4 | import com.alibaba.easyretry.common.RetryConfiguration; 5 | 6 | import lombok.Data; 7 | import lombok.experimental.Accessors; 8 | 9 | /** 10 | * @author Created by wuhao on 2021/3/19. 11 | */ 12 | @Data 13 | @Accessors(chain = true) 14 | public class RetryerInfo { 15 | 16 | /** 17 | * 执行者名称 18 | */ 19 | private String executorName; 20 | 21 | /** 22 | * 执行者方法 23 | */ 24 | private String executorMethodName; 25 | 26 | private String onFailureMethod; 27 | 28 | /** 29 | * 业务id,外部可以自定义存储一些信息 30 | */ 31 | private String bizId; 32 | 33 | private Object[] args; 34 | 35 | private Class onException; 36 | 37 | private RetryConfiguration retryConfiguration; 38 | 39 | private String namespace; 40 | 41 | private boolean reThrowException; 42 | 43 | private AbstractResultPredicate resultPredicate; 44 | 45 | } 46 | -------------------------------------------------------------------------------- /easy-retry-common/src/main/java/com/alibaba/easyretry/common/serializer/ArgDeSerializerInfo.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.common.serializer; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * @author Created by wuhao on 2020/11/1. 7 | */ 8 | @Data 9 | public class ArgDeSerializerInfo { 10 | 11 | private String argsStr; 12 | } 13 | -------------------------------------------------------------------------------- /easy-retry-common/src/main/java/com/alibaba/easyretry/common/serializer/ArgSerializerInfo.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.common.serializer; 2 | 3 | import lombok.Data; 4 | 5 | /** 6 | * @author Created by wuhao on 2020/11/1. 7 | */ 8 | @Data 9 | public class ArgSerializerInfo { 10 | 11 | /** 12 | * 执行者名称 13 | */ 14 | private String executorName; 15 | 16 | private String executorClassName; 17 | 18 | /** 19 | * 执行者方法 20 | */ 21 | private String executorMethodName; 22 | 23 | private Object[] args; 24 | } 25 | -------------------------------------------------------------------------------- /easy-retry-common/src/main/java/com/alibaba/easyretry/common/serializer/EasyRetrySerializer.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.common.serializer; 2 | 3 | /** 4 | * @author Created by wuhao on 2021/3/18. 5 | */ 6 | public interface EasyRetrySerializer { 7 | 8 | String serialize(T serializeInfo); 9 | 10 | T deSerialize(String infoStr); 11 | 12 | } 13 | -------------------------------------------------------------------------------- /easy-retry-common/src/main/java/com/alibaba/easyretry/common/serializer/ResultPredicateSerializer.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.common.serializer; 2 | 3 | import com.alibaba.easyretry.common.AbstractResultPredicate; 4 | 5 | /** 6 | * @author Created by wuhao on 2021/3/18. 7 | */ 8 | public interface ResultPredicateSerializer extends EasyRetrySerializer { 9 | 10 | } 11 | -------------------------------------------------------------------------------- /easy-retry-common/src/main/java/com/alibaba/easyretry/common/serializer/RetryArgSerializer.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.common.serializer; 2 | 3 | /** 4 | * Retry 序列化器 5 | */ 6 | public interface RetryArgSerializer extends EasyRetrySerializer { 7 | 8 | } 9 | -------------------------------------------------------------------------------- /easy-retry-common/src/main/java/com/alibaba/easyretry/common/strategy/RetryStrategy.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.common.strategy; 2 | 3 | import com.alibaba.easyretry.common.RetryContext; 4 | 5 | /** 6 | * @author Created by wuhao on 2020/11/2. 7 | */ 8 | public interface RetryStrategy { 9 | 10 | void clear(RetryContext context); 11 | } 12 | -------------------------------------------------------------------------------- /easy-retry-common/src/main/java/com/alibaba/easyretry/common/strategy/StopStrategy.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.common.strategy; 2 | 3 | import com.alibaba.easyretry.common.RetryContext; 4 | 5 | /** 6 | * @author Created by wuhao on 2020/11/1. 7 | */ 8 | public interface StopStrategy extends RetryStrategy { 9 | 10 | boolean shouldStop(RetryContext context); 11 | } 12 | -------------------------------------------------------------------------------- /easy-retry-common/src/main/java/com/alibaba/easyretry/common/strategy/WaitStrategy.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.common.strategy; 2 | 3 | import com.alibaba.easyretry.common.RetryContext; 4 | 5 | /** 6 | * @author Created by wuhao on 2020/11/1. 7 | */ 8 | public interface WaitStrategy extends RetryStrategy { 9 | 10 | boolean shouldWait(RetryContext context); 11 | 12 | void backOff(RetryContext context); 13 | } 14 | -------------------------------------------------------------------------------- /easy-retry-core/pom.xml: -------------------------------------------------------------------------------- 1 | 4 | 4.0.0 5 | 6 | com.alibaba 7 | easy-retry 8 | ${revision} 9 | ../pom.xml 10 | 11 | easy-retry-core 12 | 13 | easy-retry-core 14 | easy-retry-core 15 | 16 | 17 | ${project.groupId} 18 | easy-retry-common 19 | 20 | 21 | 22 | org.apache.commons 23 | commons-lang3 24 | 25 | 26 | 27 | com.google.guava 28 | guava 29 | 30 | 31 | 32 | com.caucho 33 | hessian 34 | 35 | 36 | 37 | org.slf4j 38 | slf4j-api 39 | 40 | 41 | 42 | com.alibaba 43 | fastjson 44 | 45 | 46 | 47 | org.apache.commons 48 | commons-collections4 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /easy-retry-core/src/main/java/com/alibaba/easyretry/core/DegradeAbleRetryExecutor.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.core; 2 | 3 | import com.alibaba.easyretry.common.RetryContext; 4 | import com.alibaba.easyretry.common.RetryExecutor; 5 | import com.alibaba.easyretry.common.constant.enums.HandleResultEnum; 6 | import com.alibaba.easyretry.core.degrade.EasyRetryDegradeHelper; 7 | import lombok.Setter; 8 | import lombok.extern.slf4j.Slf4j; 9 | 10 | /** 11 | * @author Created by gejinfeng on 2021/4/29. 12 | */ 13 | @Slf4j 14 | public class DegradeAbleRetryExecutor implements RetryExecutor { 15 | 16 | @Setter 17 | private RetryExecutor retryExecutor; 18 | 19 | @Setter 20 | private EasyRetryDegradeHelper easyRetryDegradeHelper; 21 | 22 | @Override 23 | public HandleResultEnum doExecute(RetryContext context) { 24 | if (easyRetryDegradeHelper.degrade(context)) { 25 | return HandleResultEnum.STOP; 26 | } 27 | return retryExecutor.doExecute(context); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /easy-retry-core/src/main/java/com/alibaba/easyretry/core/PersistenceRetryExecutor.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.core; 2 | 3 | import java.lang.reflect.InvocationTargetException; 4 | 5 | import com.alibaba.easyretry.common.RetryConfiguration; 6 | import com.alibaba.easyretry.common.RetryContext; 7 | import com.alibaba.easyretry.common.RetryExecutor; 8 | import com.alibaba.easyretry.common.access.RetryTaskAccess; 9 | import com.alibaba.easyretry.common.constant.enums.HandleResultEnum; 10 | import com.alibaba.easyretry.common.entity.RetryTask; 11 | import com.alibaba.easyretry.common.event.RetryEvent; 12 | import com.alibaba.easyretry.common.event.on.FailureOnRetryEvent; 13 | import com.alibaba.easyretry.common.event.on.StopOnRetryEvent; 14 | import com.alibaba.easyretry.common.event.on.SuccessOnRetryEvent; 15 | import com.alibaba.easyretry.common.filter.RetryFilterInvocation; 16 | import com.alibaba.easyretry.common.filter.RetryFilterResponse; 17 | import com.alibaba.easyretry.core.context.MaxAttemptsPersistenceRetryContext; 18 | import com.alibaba.easyretry.core.process.async.on.AbstractAsyncPersistenceOnRetryProcessor; 19 | import com.alibaba.easyretry.core.process.async.on.ExceptionPersistenceAsynOnRetryProcessor; 20 | import com.alibaba.easyretry.core.process.async.on.ResultAsynPersistenceOnRetryProcessor; 21 | import com.alibaba.easyretry.core.utils.LogUtils; 22 | import com.alibaba.easyretry.core.utils.PrintUtils; 23 | 24 | import lombok.Setter; 25 | import lombok.extern.slf4j.Slf4j; 26 | 27 | /** 28 | * @author Created by wuhao on 2021/3/2. 29 | */ 30 | @Slf4j 31 | public class PersistenceRetryExecutor implements RetryExecutor { 32 | 33 | @Setter 34 | private RetryConfiguration retryConfiguration; 35 | 36 | @Setter 37 | private RetryFilterInvocation retryFilterInvocation; 38 | 39 | @Override 40 | public HandleResultEnum doExecute(RetryContext context) { 41 | try { 42 | PrintUtils.monitorInfo("begin deal", context); 43 | return handle(context); 44 | } catch (Throwable e) { 45 | log.error("Retry invoke failed", e); 46 | return HandleResultEnum.ERROR; 47 | } 48 | } 49 | 50 | private HandleResultEnum handle(RetryContext context) { 51 | MaxAttemptsPersistenceRetryContext maxAttemptsPersistenceRetryContext 52 | = (MaxAttemptsPersistenceRetryContext)context; 53 | if (maxAttemptsPersistenceRetryContext.getWaitStrategy().shouldWait(context)) { 54 | PrintUtils.monitorInfo("shouldWait", context); 55 | return HandleResultEnum.WAITING; 56 | } 57 | PrintUtils.monitorInfo("handlingRetryTask", context); 58 | retryConfiguration.getRetryTaskAccess() 59 | .handlingRetryTask(maxAttemptsPersistenceRetryContext.getRetryTask()); 60 | AbstractAsyncPersistenceOnRetryProcessor abstractAsynPersistenceOnRetryProcessor; 61 | try { 62 | PrintUtils.monitorInfo("beigin excuteMethod", context); 63 | RetryFilterResponse retryFilterResponse = retryFilterInvocation.invoke(context); 64 | abstractAsynPersistenceOnRetryProcessor = new ResultAsynPersistenceOnRetryProcessor<>( 65 | retryFilterResponse.getResponse(), 66 | maxAttemptsPersistenceRetryContext); 67 | PrintUtils.monitorInfo("excuteMethod success ", context); 68 | } catch (Throwable t) { 69 | if (t instanceof InvocationTargetException) { 70 | t = t.getCause(); 71 | } 72 | log.error("excuteMethod failed task arg is {} task id is {}", context.getInvocation(), 73 | context.getId(), t); 74 | abstractAsynPersistenceOnRetryProcessor = new ExceptionPersistenceAsynOnRetryProcessor<>( 75 | t, 76 | maxAttemptsPersistenceRetryContext); 77 | } 78 | abstractAsynPersistenceOnRetryProcessor.process(); 79 | HandleResultEnum handleResult = abstractAsynPersistenceOnRetryProcessor.getRetryResult(); 80 | PrintUtils.monitorInfo("handleResult ", context, "handleResult is " + handleResult); 81 | RetryEvent onRetryEvent = null; 82 | switch (handleResult) { 83 | case SUCCESS: 84 | finish(context); 85 | onRetryEvent = new SuccessOnRetryEvent(context); 86 | break; 87 | case STOP: 88 | stop(context); 89 | onRetryEvent = new StopOnRetryEvent(context); 90 | break; 91 | case FAILURE: 92 | onRetryEvent = new FailureOnRetryEvent(context); 93 | } 94 | retryConfiguration.getRetryEventMulticaster().multicast(onRetryEvent); 95 | return handleResult; 96 | } 97 | 98 | private void finish(RetryContext context) { 99 | MaxAttemptsPersistenceRetryContext maxAttemptsPersistenceRetryContext 100 | = (MaxAttemptsPersistenceRetryContext)context; 101 | RetryTask retryTask = maxAttemptsPersistenceRetryContext.getRetryTask(); 102 | try { 103 | RetryTaskAccess retryTaskAccess = retryConfiguration.getRetryTaskAccess(); 104 | retryTaskAccess.finishRetryTask(retryTask); 105 | context.stop(); 106 | } catch (Throwable t) { 107 | LogUtils.CONSISTENCY_LOGGER 108 | .error("finishRetryTask error " + context.getInvocation() + " please check", t); 109 | } 110 | } 111 | 112 | private void stop(RetryContext context) { 113 | try { 114 | MaxAttemptsPersistenceRetryContext maxAttemptsPersistenceRetryContext 115 | = (MaxAttemptsPersistenceRetryContext)context; 116 | RetryTaskAccess retryTaskAccess = retryConfiguration.getRetryTaskAccess(); 117 | retryTaskAccess.stopRetryTask(maxAttemptsPersistenceRetryContext.getRetryTask()); 118 | //executeOnFailureMethod(context); 119 | context.stop(); 120 | } catch (Throwable t) { 121 | LogUtils.CONSISTENCY_LOGGER 122 | .error("stopRetryTask error " + context.getInvocation() + " please check", t); 123 | } 124 | } 125 | 126 | //private void executeOnFailureMethod(RetryContext context) { 127 | // 128 | // MaxRetryTimesRetryContext maxRetryTimesRetryContext = (MaxRetryTimesRetryContext)context; 129 | // String methodName = maxRetryTimesRetryContext.getOnFailureMethod(); 130 | // if (StringUtils.isEmpty(methodName)) { 131 | // return; 132 | // } 133 | // Object executor = context.getExecutor(); 134 | // Method onFailure = BeanUtils.getMethod(methodName, executor.getClass()); 135 | // if (Objects.isNull(onFailure)) { 136 | // return; 137 | // } 138 | // try { 139 | // onFailure.invoke(executor, context); 140 | // } catch (Throwable t) { 141 | // LogUtils.CONSISTENCY_LOGGER.error( 142 | // "executeOnFailureMethod failed onFailureMethod = {}" 143 | // + PrintUtils.printCommonMethodInfo(context) 144 | // + " please check", 145 | // methodName, 146 | // t); 147 | // } 148 | //} 149 | } 150 | -------------------------------------------------------------------------------- /easy-retry-core/src/main/java/com/alibaba/easyretry/core/PersistenceRetryer.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.core; 2 | 3 | import com.alibaba.easyretry.common.SCallable; 4 | import com.alibaba.easyretry.common.processor.AsyncPersistenceProcessor; 5 | import com.alibaba.easyretry.common.retryer.Retryer; 6 | import com.alibaba.easyretry.common.retryer.RetryerInfo; 7 | import com.alibaba.easyretry.core.process.async.before.ExceptionPersistenceAsyncBeforeRetryProcessor; 8 | import com.alibaba.easyretry.core.process.async.before.ResultAsynPersistenceBeforeRetryProcessor; 9 | import lombok.Data; 10 | import lombok.extern.slf4j.Slf4j; 11 | 12 | /** 13 | * @author Created by wuhao on 2020/11/1. 14 | */ 15 | @Slf4j 16 | @Data 17 | public class PersistenceRetryer implements Retryer { 18 | 19 | private RetryerInfo retryerInfo; 20 | 21 | public PersistenceRetryer(RetryerInfo retryerInfo) { 22 | this.retryerInfo = retryerInfo; 23 | } 24 | 25 | @Override 26 | public V call(SCallable callable) throws Throwable { 27 | AsyncPersistenceProcessor asynPersistenceProcessor; 28 | try { 29 | V result = callable.call(); 30 | asynPersistenceProcessor = new ResultAsynPersistenceBeforeRetryProcessor<>(result, 31 | retryerInfo); 32 | } catch (Throwable e) { 33 | log.error( 34 | "call method error executorMethodName is {} executorName name is {} args is {}", 35 | retryerInfo.getExecutorMethodName(), 36 | retryerInfo.getExecutorName(), 37 | retryerInfo.getArgs(), 38 | e); 39 | asynPersistenceProcessor = new ExceptionPersistenceAsyncBeforeRetryProcessor<>(e, 40 | retryerInfo); 41 | } 42 | asynPersistenceProcessor.process(); 43 | return asynPersistenceProcessor.getResult(); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /easy-retry-core/src/main/java/com/alibaba/easyretry/core/PersistenceRetryerBuilder.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.core; 2 | 3 | import com.alibaba.easyretry.common.AbstractResultPredicate; 4 | import com.alibaba.easyretry.common.RetryConfiguration; 5 | import com.alibaba.easyretry.common.retryer.RetryerInfo; 6 | 7 | /** 8 | * @author Created by wuhao on 2020/11/1. 9 | */ 10 | public class PersistenceRetryerBuilder { 11 | 12 | private PersistenceRetryer persistenceRetryer; 13 | 14 | public PersistenceRetryerBuilder(RetryConfiguration retryConfiguration) { 15 | RetryerInfo retryerInfo = new RetryerInfo<>(); 16 | persistenceRetryer = new PersistenceRetryer(retryerInfo); 17 | } 18 | 19 | public static PersistenceRetryerBuilder of(RetryConfiguration retryConfiguration) { 20 | return new PersistenceRetryerBuilder<>(retryConfiguration); 21 | } 22 | 23 | public PersistenceRetryerBuilder withExecutorName(String executorName) { 24 | persistenceRetryer.getRetryerInfo().setExecutorName(executorName); 25 | return this; 26 | } 27 | 28 | public PersistenceRetryerBuilder withExecutorMethodName(String executorMethodName) { 29 | persistenceRetryer.getRetryerInfo().setExecutorMethodName(executorMethodName); 30 | return this; 31 | } 32 | 33 | public PersistenceRetryerBuilder withBizId(String bizId) { 34 | persistenceRetryer.getRetryerInfo().setBizId(bizId); 35 | return this; 36 | } 37 | 38 | public PersistenceRetryerBuilder withArgs(Object[] args) { 39 | persistenceRetryer.getRetryerInfo().setArgs(args); 40 | return this; 41 | } 42 | 43 | public PersistenceRetryerBuilder withOnException(Class onException) { 44 | persistenceRetryer.getRetryerInfo().setOnException(onException); 45 | return this; 46 | } 47 | 48 | public PersistenceRetryerBuilder withOnFailureMethod(String onFailureMethod) { 49 | persistenceRetryer.getRetryerInfo().setOnFailureMethod(onFailureMethod); 50 | return this; 51 | } 52 | 53 | public PersistenceRetryerBuilder withReThrowException(boolean reThrowException) { 54 | persistenceRetryer.getRetryerInfo().setReThrowException(reThrowException); 55 | return this; 56 | } 57 | 58 | public PersistenceRetryerBuilder withNamespace(String namespace) { 59 | persistenceRetryer.getRetryerInfo().setNamespace(namespace); 60 | return this; 61 | } 62 | 63 | public PersistenceRetryerBuilder withConfiguration(RetryConfiguration retryConfiguration) { 64 | persistenceRetryer.getRetryerInfo().setRetryConfiguration(retryConfiguration); 65 | return this; 66 | } 67 | 68 | public PersistenceRetryerBuilder withResultPredicate(AbstractResultPredicate abstractResultPredicate) { 69 | persistenceRetryer.getRetryerInfo().setResultPredicate(abstractResultPredicate); 70 | return this; 71 | } 72 | 73 | public PersistenceRetryer build() { 74 | return persistenceRetryer; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /easy-retry-core/src/main/java/com/alibaba/easyretry/core/RetryerBuilder.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.core; 2 | 3 | import com.alibaba.easyretry.common.AbstractResultPredicate; 4 | import com.alibaba.easyretry.common.RetryConfiguration; 5 | import com.alibaba.easyretry.common.constant.enums.RetryTypeEnum; 6 | import com.alibaba.easyretry.common.retryer.Retryer; 7 | 8 | /** 9 | * @author Created by zhangchi on 2023-07-13 10 | */ 11 | public class RetryerBuilder { 12 | 13 | /** 14 | * 执行者名称 15 | */ 16 | private String executorNameContext; 17 | 18 | /** 19 | * 执行者方法 20 | */ 21 | private String executorMethodNameContext; 22 | 23 | private String onFailureMethodContext; 24 | 25 | /** 26 | * 业务id,外部可以自定义存储一些信息 27 | */ 28 | private String bizIdContext; 29 | 30 | private Object[] argsContext; 31 | 32 | private Class onExceptionContext; 33 | 34 | private RetryConfiguration retryConfigurationContext; 35 | 36 | private String namespaceContext; 37 | 38 | private boolean reThrowExceptionContext; 39 | 40 | private AbstractResultPredicate resultPredicateContext; 41 | 42 | 43 | public RetryerBuilder withExecutorName(String executorName) { 44 | executorNameContext = executorName; 45 | return this; 46 | } 47 | 48 | public RetryerBuilder withExecutorMethodName(String executorMethodName) { 49 | executorMethodNameContext = executorMethodName; 50 | return this; 51 | } 52 | 53 | public RetryerBuilder withBizId(String bizId) { 54 | bizIdContext = bizId; 55 | return this; 56 | } 57 | 58 | public RetryerBuilder withArgs(Object[] args) { 59 | argsContext = args; 60 | return this; 61 | } 62 | 63 | public RetryerBuilder withOnException(Class onException) { 64 | onExceptionContext = onException; 65 | return this; 66 | } 67 | 68 | public RetryerBuilder withOnFailureMethod(String onFailureMethod) { 69 | onFailureMethodContext = onFailureMethod; 70 | return this; 71 | } 72 | 73 | public RetryerBuilder withReThrowException(boolean reThrowException) { 74 | reThrowExceptionContext = reThrowException; 75 | return this; 76 | } 77 | 78 | public RetryerBuilder withNamespace(String namespace) { 79 | namespaceContext = namespace; 80 | return this; 81 | } 82 | 83 | public RetryerBuilder withConfiguration(RetryConfiguration retryConfiguration) { 84 | retryConfigurationContext = retryConfiguration; 85 | return this; 86 | } 87 | 88 | public RetryerBuilder withResultPredicate(AbstractResultPredicate abstractResultPredicate) { 89 | resultPredicateContext = abstractResultPredicate; 90 | return this; 91 | } 92 | 93 | public Retryer build(RetryTypeEnum retryTypeEnum) { 94 | if (RetryTypeEnum.SYNC == retryTypeEnum) { 95 | return buildSyncRetryer(); 96 | } else { 97 | return buildAsyncRetryer(); 98 | } 99 | } 100 | 101 | private SyncRetryer buildSyncRetryer() { 102 | SyncRetryerBuilder builder = SyncRetryerBuilder.of(retryConfigurationContext) 103 | .withConfiguration(retryConfigurationContext); 104 | return builder.build(); 105 | } 106 | 107 | private PersistenceRetryer buildAsyncRetryer() { 108 | PersistenceRetryerBuilder builder = PersistenceRetryerBuilder.of(retryConfigurationContext) 109 | .withExecutorName(executorNameContext) 110 | .withExecutorMethodName(executorMethodNameContext) 111 | .withArgs(argsContext) 112 | .withConfiguration(retryConfigurationContext) 113 | // .withOnFailureMethod(retryable.onFailureMethod()) 114 | // .withNamespace(namespace) 115 | .withReThrowException(reThrowExceptionContext) 116 | .withResultPredicate(resultPredicateContext); 117 | return builder.build(); 118 | } 119 | 120 | } 121 | -------------------------------------------------------------------------------- /easy-retry-core/src/main/java/com/alibaba/easyretry/core/SyncRetryer.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.core; 2 | 3 | 4 | import com.alibaba.easyretry.common.AbstractRetrySyncExecutor; 5 | import com.alibaba.easyretry.common.SCallable; 6 | import com.alibaba.easyretry.common.retryer.Retryer; 7 | import com.alibaba.easyretry.common.retryer.RetryerInfo; 8 | 9 | import lombok.Data; 10 | import lombok.extern.slf4j.Slf4j; 11 | 12 | /** 13 | * @author Created by zhangchi Created on 2023-07-12 14 | */ 15 | @Slf4j 16 | @Data 17 | public class SyncRetryer implements Retryer { 18 | 19 | private RetryerInfo retryerInfo; 20 | 21 | public SyncRetryer(RetryerInfo retryerInfo) { 22 | this.retryerInfo = retryerInfo; 23 | } 24 | 25 | @Override 26 | public V call(SCallable callable) throws Throwable { 27 | AbstractRetrySyncExecutor retrySyncExecutor = retryerInfo.getRetryConfiguration().getRetrySyncExecutor(); 28 | retrySyncExecutor.setRetryerInfo(retryerInfo); 29 | return (V) retrySyncExecutor.call(callable); 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /easy-retry-core/src/main/java/com/alibaba/easyretry/core/SyncRetryerBuilder.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.core; 2 | 3 | import java.util.Objects; 4 | 5 | import com.alibaba.easyretry.common.RetryConfiguration; 6 | import com.alibaba.easyretry.common.retryer.RetryerInfo; 7 | 8 | /** 9 | * @author Created by zhangchi on 2023-07-12 10 | */ 11 | public class SyncRetryerBuilder { 12 | 13 | private SyncRetryer syncRetryer; 14 | 15 | public SyncRetryerBuilder(RetryConfiguration retryConfiguration) { 16 | RetryerInfo retryerInfo = new RetryerInfo<>(); 17 | syncRetryer = new SyncRetryer<>(retryerInfo); 18 | } 19 | 20 | public static SyncRetryerBuilder of(RetryConfiguration retryConfiguration) { 21 | return new SyncRetryerBuilder<>(retryConfiguration); 22 | } 23 | 24 | public SyncRetryerBuilder withConfiguration(RetryConfiguration retryConfiguration) { 25 | syncRetryer.getRetryerInfo().setRetryConfiguration(retryConfiguration); 26 | return this; 27 | } 28 | 29 | 30 | public SyncRetryer build() { 31 | return syncRetryer; 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /easy-retry-core/src/main/java/com/alibaba/easyretry/core/access/DefaultRetrySerializerAccess.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.core.access; 2 | 3 | import com.alibaba.easyretry.common.access.RetrySerializerAccess; 4 | import com.alibaba.easyretry.common.serializer.RetryArgSerializer; 5 | import com.alibaba.easyretry.core.serializer.HessianRetryArgSerializer; 6 | 7 | /** 8 | * @author Created by wuhao on 2020/11/6. 9 | */ 10 | public class DefaultRetrySerializerAccess implements RetrySerializerAccess { 11 | 12 | @Override 13 | public RetryArgSerializer getCurrentGlobalRetrySerializer() { 14 | return new HessianRetryArgSerializer(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /easy-retry-core/src/main/java/com/alibaba/easyretry/core/access/MemoryRetryTaskAccess.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.core.access; 2 | 3 | import java.util.List; 4 | import java.util.Map; 5 | import java.util.concurrent.atomic.AtomicLong; 6 | import java.util.stream.Collectors; 7 | 8 | import com.alibaba.easyretry.common.access.RetryTaskAccess; 9 | import com.alibaba.easyretry.common.constant.enums.RetryTaskStatusEnum; 10 | import com.alibaba.easyretry.common.entity.RetryTask; 11 | 12 | import com.google.common.collect.Maps; 13 | 14 | /** 15 | * @author Created by wuhao on 2020/11/5. 16 | */ 17 | public class MemoryRetryTaskAccess implements RetryTaskAccess { 18 | 19 | private static final Map retryTaskMap = Maps.newConcurrentMap(); 20 | 21 | private static final AtomicLong atomicLong = new AtomicLong(); 22 | 23 | @Override 24 | public boolean saveRetryTask(RetryTask retryTask) { 25 | long id = atomicLong.getAndIncrement(); 26 | retryTask.setId(id); 27 | retryTaskMap.putIfAbsent(id, retryTask); 28 | return true; 29 | } 30 | 31 | @Override 32 | public boolean handlingRetryTask(RetryTask retryTask) { 33 | retryTask.setStatus(RetryTaskStatusEnum.HANDLING); 34 | retryTaskMap.putIfAbsent(retryTask.getId(), retryTask); 35 | return true; 36 | } 37 | 38 | @Override 39 | public boolean finishRetryTask(RetryTask retryTask) { 40 | retryTaskMap.remove(retryTask.getId()); 41 | return true; 42 | } 43 | 44 | @Override 45 | public boolean stopRetryTask(RetryTask retryTask) { 46 | retryTask.setStatus(RetryTaskStatusEnum.ERROR); 47 | retryTaskMap.putIfAbsent(retryTask.getId(), retryTask); 48 | return false; 49 | } 50 | 51 | @Override 52 | public List listAvailableTasks(Long lastId) { 53 | return retryTaskMap.values().stream() 54 | .filter((retryTask) -> retryTask.getStatus() == RetryTaskStatusEnum.INIT) 55 | .filter((retryTask) -> retryTask.getId() > lastId) 56 | .sorted((o1, o2) -> o1.getId() > o2.getId() ? 1 : -1) 57 | .collect(Collectors.toList()); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /easy-retry-core/src/main/java/com/alibaba/easyretry/core/container/SimpleRetryContainer.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.core.container; 2 | 3 | import java.util.List; 4 | import java.util.concurrent.BlockingQueue; 5 | import java.util.concurrent.LinkedBlockingQueue; 6 | import java.util.concurrent.PriorityBlockingQueue; 7 | import java.util.concurrent.ThreadPoolExecutor; 8 | import java.util.concurrent.TimeUnit; 9 | 10 | import com.alibaba.easyretry.common.RetryConfiguration; 11 | import com.alibaba.easyretry.common.RetryContainer; 12 | import com.alibaba.easyretry.common.RetryContext; 13 | import com.alibaba.easyretry.common.RetryExecutor; 14 | import com.alibaba.easyretry.common.constant.enums.HandleResultEnum; 15 | import com.alibaba.easyretry.common.entity.RetryTask; 16 | import com.alibaba.easyretry.core.context.MaxAttemptsPersistenceRetryContext.RetryContextBuilder; 17 | 18 | import lombok.extern.slf4j.Slf4j; 19 | import org.apache.commons.collections4.CollectionUtils; 20 | 21 | /** 22 | * @author Created by wuhao on 2020/11/5. 23 | */ 24 | @Slf4j 25 | public class SimpleRetryContainer implements RetryContainer { 26 | 27 | private static final Integer MAX_QUEUE_SIZE = 2000; 28 | 29 | private RetryConfiguration retryConfiguration; 30 | 31 | private RetryExecutor retryExecutor; 32 | 33 | public SimpleRetryContainer() { 34 | } 35 | 36 | public SimpleRetryContainer( 37 | RetryConfiguration retryConfiguration, RetryExecutor retryExecutor) { 38 | this.retryConfiguration = retryConfiguration; 39 | this.retryExecutor = retryExecutor; 40 | } 41 | 42 | @Override 43 | public void start() { 44 | BlockingQueue queue = new PriorityBlockingQueue<>(MAX_QUEUE_SIZE); 45 | ThreadPoolExecutor retryExecutor = 46 | new ThreadPoolExecutor( 47 | 1, 48 | 1, 49 | 0L, 50 | TimeUnit.MILLISECONDS, 51 | new LinkedBlockingQueue<>(), 52 | r -> new Thread(r, "retryExecutor-Thread")); 53 | retryExecutor.execute(new TaskConsumer(queue)); 54 | ThreadPoolExecutor retrySelector = 55 | new ThreadPoolExecutor( 56 | 1, 57 | 1, 58 | 0L, 59 | TimeUnit.MILLISECONDS, 60 | new LinkedBlockingQueue<>(), 61 | r -> new Thread(r, "retrySelector-Thread")); 62 | retrySelector.execute(new TaskProducer(queue)); 63 | } 64 | 65 | @Override 66 | public void stop() { 67 | } 68 | 69 | public class TaskConsumer implements Runnable { 70 | 71 | private static final long MAX_SLEEP_TIME_MILLISECONDS = 10 * 1000L; 72 | private static final long SLEEP_BASE_TIME_MILLISECONDS = 1000L; 73 | private final BlockingQueue queue; 74 | private long sleepTimes = 0L; 75 | 76 | private TaskConsumer(BlockingQueue queue) { 77 | this.queue = queue; 78 | } 79 | 80 | @Override 81 | public void run() { 82 | while (!Thread.currentThread().isInterrupted()) { 83 | doExecute(); 84 | long totalTime = sleepTimes * SLEEP_BASE_TIME_MILLISECONDS; 85 | try { 86 | TimeUnit.MILLISECONDS.sleep(Math.min(totalTime, MAX_SLEEP_TIME_MILLISECONDS)); 87 | } catch (InterruptedException e) { 88 | log.error("taskConsumer interruptedException error", e); 89 | } 90 | } 91 | } 92 | 93 | private void doExecute() { 94 | try { 95 | RetryContext context = queue.take(); 96 | HandleResultEnum result = retryExecutor.doExecute(context); 97 | if (HandleResultEnum.SUCCESS == result) { 98 | sleepTimes = 0L; 99 | } else if (HandleResultEnum.FAILURE == result) { 100 | sleepTimes = 0L; 101 | queue.add(context); 102 | } else if (HandleResultEnum.STOP == result) { 103 | sleepTimes = 0L; 104 | } else if (HandleResultEnum.ERROR == result) { 105 | sleepTimes = 0L; 106 | // do nothing 107 | } else { 108 | sleepTimes++; 109 | queue.add(context); 110 | } 111 | } catch (InterruptedException e) { 112 | log.error("Retry execute failed when getting retry task", e); 113 | } catch (Throwable e) { 114 | log.error("Retry invoke failed", e); 115 | } 116 | } 117 | } 118 | 119 | public class TaskProducer implements Runnable { 120 | 121 | private static final long MAX_SLEEP_TIME_MILLISECONDS = 10 * 1000L; 122 | private static final long SLEEP_BASE_TIME_MILLISECONDS = 1000L; 123 | 124 | private final BlockingQueue queue; 125 | 126 | private long sleepTimes = 0L; 127 | 128 | private volatile Long lastId = -1L; 129 | 130 | public TaskProducer(BlockingQueue queue) { 131 | this.queue = queue; 132 | } 133 | 134 | @Override 135 | public void run() { 136 | while (!Thread.currentThread().isInterrupted()) { 137 | doSelect(); 138 | long totalTime = 139 | sleepTimes * SLEEP_BASE_TIME_MILLISECONDS + SLEEP_BASE_TIME_MILLISECONDS; 140 | try { 141 | TimeUnit.MILLISECONDS.sleep(Math.min(totalTime, MAX_SLEEP_TIME_MILLISECONDS)); 142 | } catch (InterruptedException e) { 143 | log.error("taskConsumer interruptedException error", e); 144 | } 145 | } 146 | } 147 | 148 | private void doSelect() { 149 | if (queue.size() >= MAX_QUEUE_SIZE) { 150 | sleepTimes++; 151 | return; 152 | } 153 | 154 | List tasks = 155 | retryConfiguration.getRetryTaskAccess().listAvailableTasks(lastId); 156 | if (CollectionUtils.isEmpty(tasks)) { 157 | sleepTimes++; 158 | return; 159 | } 160 | if (queue.size() >= MAX_QUEUE_SIZE) { 161 | sleepTimes++; 162 | return; 163 | } 164 | if (queue.size() + tasks.size() >= MAX_QUEUE_SIZE) { 165 | sleepTimes++; 166 | } else { 167 | sleepTimes = 0L; 168 | } 169 | for (RetryTask task : tasks) { 170 | try { 171 | lastId = task.getId(); 172 | RetryContext retryContext = 173 | new RetryContextBuilder(retryConfiguration, task) 174 | .buildInvocation() 175 | .buildRetryArgSerializer() 176 | .buildStopStrategy() 177 | .buildWaitStrategy() 178 | .buildRetryTask() 179 | .buildMaxRetryTimes() 180 | .buildOnFailureMethod() 181 | .buildPriority(0L) 182 | .buildResultPredicateSerializer() 183 | .build(); 184 | retryContext.start(); 185 | 186 | queue.put(retryContext); 187 | log.warn("add retry task to queue, task:{}", 188 | task.getId()); 189 | } catch (Throwable e) { 190 | log.error("add retry task to queue , task:{}", 191 | task.getId(), e); 192 | // 出现异常task将放不进queue中,就不会再重试了 193 | // 是否需要更新task的状态,并且加上失败的原因? 194 | } 195 | } 196 | } 197 | } 198 | } 199 | -------------------------------------------------------------------------------- /easy-retry-core/src/main/java/com/alibaba/easyretry/core/context/MaxAttemptsPersistenceRetryContext.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.core.context; 2 | 3 | import java.lang.reflect.Method; 4 | import java.util.Map; 5 | import java.util.Objects; 6 | import java.util.concurrent.TimeUnit; 7 | import java.util.stream.Stream; 8 | 9 | import com.alibaba.easyretry.common.Invocation; 10 | import com.alibaba.easyretry.common.RetryConfiguration; 11 | import com.alibaba.easyretry.common.RetryContext; 12 | import com.alibaba.easyretry.common.RetryLifecycle; 13 | import com.alibaba.easyretry.common.SimpleMethodInvocation; 14 | import com.alibaba.easyretry.common.entity.RetryTask; 15 | import com.alibaba.easyretry.common.serializer.ResultPredicateSerializer; 16 | import com.alibaba.easyretry.common.serializer.RetryArgSerializer; 17 | import com.alibaba.easyretry.common.strategy.StopStrategy; 18 | import com.alibaba.easyretry.common.strategy.WaitStrategy; 19 | 20 | import com.google.common.collect.Maps; 21 | import lombok.Data; 22 | import lombok.ToString; 23 | import org.apache.commons.lang3.reflect.MethodUtils; 24 | 25 | @Data 26 | @ToString(callSuper = true) 27 | public class MaxAttemptsPersistenceRetryContext implements RetryContext, RetryLifecycle, 28 | Comparable { 29 | 30 | private RetryTask retryTask; 31 | 32 | private RetryArgSerializer retryArgSerializer; 33 | 34 | private ResultPredicateSerializer resultPredicateSerializer; 35 | 36 | private Long priority; 37 | 38 | private StopStrategy stopStrategy; 39 | 40 | private WaitStrategy waitStrategy; 41 | 42 | private int maxRetryTimes; 43 | 44 | private String onFailureMethod; 45 | 46 | private Invocation invocation; 47 | 48 | @Override 49 | public int compareTo(MaxAttemptsPersistenceRetryContext o) { 50 | return this.priority > o.getPriority() ? 1 : -1; 51 | } 52 | 53 | @Override 54 | public void start() { 55 | } 56 | 57 | @Override 58 | public void stop() { 59 | stopStrategy.clear(this); 60 | waitStrategy.clear(this); 61 | } 62 | 63 | @Override 64 | public void setAttribute(String key, String value) { 65 | Map extAttrs = retryTask.getExtAttrs(); 66 | if (Objects.isNull(extAttrs)) { 67 | extAttrs = Maps.newHashMap(); 68 | } 69 | extAttrs.put(key, value); 70 | } 71 | 72 | @Override 73 | public String getAttribute(String key) { 74 | Map extAttrs = retryTask.getExtAttrs(); 75 | if (Objects.isNull(extAttrs)) { 76 | return null; 77 | } else { 78 | return extAttrs.get(key); 79 | } 80 | } 81 | 82 | public Long getNextRetryTime(TimeUnit unit) { 83 | return unit.convert(priority, TimeUnit.MILLISECONDS); 84 | } 85 | 86 | public void setNextRetryTime(Long nexRetryTime, TimeUnit unit) { 87 | priority = unit.toMillis(nexRetryTime); 88 | } 89 | 90 | @Override 91 | public String getId() { 92 | return retryTask.getId() + ""; 93 | } 94 | 95 | public static class RetryContextBuilder { 96 | 97 | private MaxAttemptsPersistenceRetryContext retryContext; 98 | 99 | private RetryConfiguration retryConfiguration; 100 | 101 | private RetryTask retryTask; 102 | 103 | public RetryContextBuilder(RetryConfiguration retryConfiguration, RetryTask retryTask) { 104 | retryContext = new MaxAttemptsPersistenceRetryContext(); 105 | this.retryConfiguration = retryConfiguration; 106 | this.retryTask = retryTask; 107 | } 108 | 109 | public RetryContextBuilder buildInvocation() { 110 | RetryArgSerializer retryArgSerializer = retryConfiguration.getRetrySerializerAccess() 111 | .getCurrentGlobalRetrySerializer(); 112 | Object[] args = retryArgSerializer.deSerialize(retryTask.getArgsStr()).getArgs(); 113 | Object executor = retryConfiguration.getExecutorSolver() 114 | .resolver(retryTask.getExecutorName()); 115 | Class[] classes = Stream.of(args).map(Object::getClass).toArray(Class[]::new); 116 | Method method = MethodUtils 117 | .getMatchingMethod(executor.getClass(), retryTask.getExecutorMethodName(), classes); 118 | SimpleMethodInvocation simpleMethodInvocation = new SimpleMethodInvocation(executor, 119 | method, args); 120 | retryContext.setInvocation(simpleMethodInvocation); 121 | return this; 122 | } 123 | 124 | public RetryContextBuilder buildRetryArgSerializer() { 125 | retryContext.setRetryArgSerializer( 126 | retryConfiguration.getRetrySerializerAccess().getCurrentGlobalRetrySerializer()); 127 | return this; 128 | } 129 | 130 | public RetryContextBuilder buildStopStrategy() { 131 | retryContext.setStopStrategy( 132 | retryConfiguration.getRetryStrategyAccess().getCurrentGlobalStopStrategy()); 133 | return this; 134 | } 135 | 136 | public RetryContextBuilder buildWaitStrategy() { 137 | retryContext.setWaitStrategy( 138 | retryConfiguration.getRetryStrategyAccess().getCurrentGlobalWaitStrategy()); 139 | return this; 140 | } 141 | 142 | public RetryContextBuilder buildRetryTask() { 143 | retryContext.setRetryTask(retryTask); 144 | return this; 145 | } 146 | 147 | public RetryContextBuilder buildMaxRetryTimes() { 148 | retryContext.setMaxRetryTimes(retryConfiguration.getMaxRetryTimes()); 149 | return this; 150 | } 151 | 152 | public RetryContextBuilder buildOnFailureMethod() { 153 | retryContext.setOnFailureMethod(retryTask.getOnFailureMethod()); 154 | return this; 155 | } 156 | 157 | public RetryContextBuilder buildResultPredicateSerializer() { 158 | retryContext 159 | .setResultPredicateSerializer(retryConfiguration.getResultPredicateSerializer()); 160 | return this; 161 | } 162 | 163 | public RetryContextBuilder buildPriority(Long priority) { 164 | retryContext.setPriority(priority); 165 | return this; 166 | } 167 | 168 | public MaxAttemptsPersistenceRetryContext build() { 169 | return retryContext; 170 | } 171 | } 172 | } 173 | -------------------------------------------------------------------------------- /easy-retry-core/src/main/java/com/alibaba/easyretry/core/degrade/EasyRetryDegradeHelper.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.core.degrade; 2 | 3 | import com.alibaba.easyretry.common.RetryContext; 4 | 5 | /** 6 | * @author Created by gejinfeng on 2021/4/29. 7 | */ 8 | public interface EasyRetryDegradeHelper { 9 | 10 | /** 11 | * 是否降级 12 | * 13 | * @param retryContext retryContext 14 | * @return degrade 15 | */ 16 | boolean degrade(RetryContext retryContext); 17 | 18 | } 19 | -------------------------------------------------------------------------------- /easy-retry-core/src/main/java/com/alibaba/easyretry/core/event/SimpleRetryEventMulticaster.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.core.event; 2 | 3 | import java.util.List; 4 | import java.util.Objects; 5 | 6 | import com.alibaba.easyretry.common.event.RetryEvent; 7 | import com.alibaba.easyretry.common.event.RetryEventMulticaster; 8 | import com.alibaba.easyretry.common.event.RetryListener; 9 | 10 | import com.google.common.collect.Lists; 11 | import lombok.Setter; 12 | 13 | /** 14 | * @author Created by wuhao on 2021/3/26. 15 | */ 16 | public class SimpleRetryEventMulticaster implements RetryEventMulticaster { 17 | 18 | @Setter 19 | private List listenerCaches = Lists.newArrayList(); 20 | 21 | @Override 22 | public void register(RetryListener listener) { 23 | listenerCaches.add(listener); 24 | } 25 | 26 | @Override 27 | public void multicast(RetryEvent retryEvent) { 28 | if (Objects.isNull(retryEvent)) { 29 | return; 30 | } 31 | listenerCaches.forEach((retryListener) -> retryListener.onRetryEvent(retryEvent)); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /easy-retry-core/src/main/java/com/alibaba/easyretry/core/filter/DefaultRetryFilterInvocationHandler.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.core.filter; 2 | 3 | import java.util.List; 4 | 5 | import com.alibaba.easyretry.common.RetryContext; 6 | import com.alibaba.easyretry.common.filter.RetryFilter; 7 | import com.alibaba.easyretry.common.filter.RetryFilterInvocation; 8 | import com.alibaba.easyretry.common.filter.RetryFilterInvocationHandler; 9 | import com.alibaba.easyretry.common.filter.RetryFilterRegister; 10 | import com.alibaba.easyretry.common.filter.RetryFilterResponse; 11 | 12 | import lombok.Setter; 13 | import org.apache.commons.collections4.CollectionUtils; 14 | 15 | /** 16 | * @author Created by wuhao on 2021/3/22. 17 | */ 18 | public class DefaultRetryFilterInvocationHandler implements RetryFilterInvocationHandler, RetryFilterInvocation { 19 | 20 | private RetryFilter firstFilter; 21 | 22 | @Setter 23 | private RetryFilterRegister retryFilterRegister; 24 | 25 | @Override 26 | public RetryFilterResponse invoke(RetryContext retryContext) throws Throwable { 27 | return firstFilter.doFilter(retryContext); 28 | } 29 | 30 | @Override 31 | public void handle() { 32 | List retryFilters = retryFilterRegister.export(); 33 | firstFilter = new NOOPRetryFilter(); 34 | RetryFilter lastRetryFilter = firstFilter; 35 | 36 | for (RetryFilter retryFilter : CollectionUtils.emptyIfNull(retryFilters)) { 37 | lastRetryFilter.setNext(retryFilter); 38 | lastRetryFilter = retryFilter; 39 | } 40 | 41 | IdentifyRetryFilter identifyRetryFilter = new IdentifyRetryFilter(); 42 | lastRetryFilter.setNext(identifyRetryFilter); 43 | lastRetryFilter = identifyRetryFilter; 44 | 45 | MethodExcuteRetryFilter methodExcuteRetryFilter = new MethodExcuteRetryFilter(); 46 | lastRetryFilter.setNext(methodExcuteRetryFilter); 47 | 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /easy-retry-core/src/main/java/com/alibaba/easyretry/core/filter/DefaultRetryFilterRegisterHandler.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.core.filter; 2 | 3 | import java.util.List; 4 | 5 | import com.alibaba.easyretry.common.filter.RetryFilter; 6 | import com.alibaba.easyretry.common.filter.RetryFilterDiscover; 7 | import com.alibaba.easyretry.common.filter.RetryFilterRegister; 8 | import com.alibaba.easyretry.common.filter.RetryFilterRegisterHandler; 9 | 10 | import lombok.Setter; 11 | import org.apache.commons.collections4.CollectionUtils; 12 | 13 | /** 14 | * @author Created by wuhao on 2021/4/9. 15 | */ 16 | public class DefaultRetryFilterRegisterHandler implements RetryFilterRegisterHandler { 17 | 18 | @Setter 19 | private RetryFilterDiscover retryFilterDiscover; 20 | 21 | @Setter 22 | private RetryFilterRegister retryFilterRegister; 23 | 24 | @Override 25 | public void handle() { 26 | List retryFilters = retryFilterDiscover.discoverAll(); 27 | for (RetryFilter retryFilter : CollectionUtils.emptyIfNull(retryFilters)) { 28 | retryFilterRegister.register(retryFilter); 29 | } 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /easy-retry-core/src/main/java/com/alibaba/easyretry/core/filter/IdentifyRetryFilter.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.core.filter; 2 | 3 | import com.alibaba.easyretry.common.RetryContext; 4 | import com.alibaba.easyretry.common.RetryIdentify; 5 | import com.alibaba.easyretry.common.filter.AbstractRetryFilter; 6 | import com.alibaba.easyretry.common.filter.RetryFilterResponse; 7 | 8 | /** 9 | * @author Created by wuhao on 2021/3/22. 10 | */ 11 | public class IdentifyRetryFilter extends AbstractRetryFilter { 12 | 13 | @Override 14 | public RetryFilterResponse doFilter(RetryContext retryContext) throws Throwable { 15 | try { 16 | RetryIdentify.start(); 17 | return next.doFilter(retryContext); 18 | } finally { 19 | RetryIdentify.stop(); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /easy-retry-core/src/main/java/com/alibaba/easyretry/core/filter/MethodExcuteRetryFilter.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.core.filter; 2 | 3 | import com.alibaba.easyretry.common.RetryContext; 4 | import com.alibaba.easyretry.common.filter.RetryFilter; 5 | import com.alibaba.easyretry.common.filter.RetryFilterResponse; 6 | 7 | /** 8 | * @author Created by wuhao on 2021/3/22. 9 | */ 10 | public class MethodExcuteRetryFilter implements RetryFilter { 11 | 12 | @Override 13 | public RetryFilterResponse doFilter(RetryContext retryContext) throws Throwable { 14 | RetryFilterResponse retryFilterResponse = new RetryFilterResponse(); 15 | retryFilterResponse.setResponse(retryContext.getInvocation().invoke()); 16 | return retryFilterResponse; 17 | } 18 | 19 | @Override 20 | public void setNext(RetryFilter next) { 21 | 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /easy-retry-core/src/main/java/com/alibaba/easyretry/core/filter/NOOPRetryFilter.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.core.filter; 2 | 3 | import com.alibaba.easyretry.common.RetryContext; 4 | import com.alibaba.easyretry.common.filter.AbstractRetryFilter; 5 | import com.alibaba.easyretry.common.filter.RetryFilterResponse; 6 | 7 | /** 8 | * @author Created by wuhao on 2021/3/22. 9 | */ 10 | public class NOOPRetryFilter extends AbstractRetryFilter { 11 | 12 | @Override 13 | public RetryFilterResponse doFilter(RetryContext retryContext) throws Throwable { 14 | return next.doFilter(retryContext); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /easy-retry-core/src/main/java/com/alibaba/easyretry/core/filter/SPIRetryFilterDiscover.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.core.filter; 2 | 3 | import java.util.Iterator; 4 | import java.util.List; 5 | import java.util.ServiceLoader; 6 | 7 | import com.alibaba.easyretry.common.filter.RetryFilter; 8 | import com.alibaba.easyretry.common.filter.RetryFilterDiscover; 9 | 10 | import com.google.common.collect.Lists; 11 | 12 | /** 13 | * @author Created by wuhao on 2021/4/9. 14 | */ 15 | public class SPIRetryFilterDiscover implements RetryFilterDiscover { 16 | 17 | @Override 18 | public List discoverAll() { 19 | ServiceLoader retryFilters = ServiceLoader.load(RetryFilter.class); 20 | Iterator iterator = retryFilters.iterator(); 21 | return Lists.newArrayList(iterator); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /easy-retry-core/src/main/java/com/alibaba/easyretry/core/filter/SimpleRetryFilterRegister.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.core.filter; 2 | 3 | import java.util.List; 4 | 5 | import com.alibaba.easyretry.common.filter.RetryFilter; 6 | import com.alibaba.easyretry.common.filter.RetryFilterRegister; 7 | 8 | import com.google.common.collect.Lists; 9 | 10 | /** 11 | * @author Created by wuhao on 2021/4/9. 12 | */ 13 | public class SimpleRetryFilterRegister implements RetryFilterRegister { 14 | 15 | private List retryFiltersCache = Lists.newArrayList(); 16 | 17 | @Override 18 | public void register(RetryFilter retryFilter) { 19 | retryFiltersCache.add(retryFilter); 20 | } 21 | 22 | @Override 23 | public List export() { 24 | return retryFiltersCache; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /easy-retry-core/src/main/java/com/alibaba/easyretry/core/process/async/AbstractAsyncPersistenceProcessor.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.core.process.async; 2 | 3 | import com.alibaba.easyretry.common.processor.AsyncPersistenceProcessor; 4 | import lombok.extern.slf4j.Slf4j; 5 | 6 | /** 7 | * @author Created by wuhao on 2021/3/19. 8 | */ 9 | @Slf4j 10 | public abstract class AbstractAsyncPersistenceProcessor implements AsyncPersistenceProcessor { 11 | 12 | @Override 13 | public void process() { 14 | if (!needRetry()) { 15 | return; 16 | } 17 | doProcess(); 18 | } 19 | 20 | protected abstract void doProcess(); 21 | 22 | @Override 23 | public abstract boolean needRetry(); 24 | 25 | } 26 | -------------------------------------------------------------------------------- /easy-retry-core/src/main/java/com/alibaba/easyretry/core/process/async/before/AbstractAsyncPersistenceBeforeRetryProcessor.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.core.process.async.before; 2 | 3 | import java.util.Date; 4 | import java.util.Map; 5 | import java.util.Objects; 6 | 7 | import com.alibaba.easyretry.common.RetryConfiguration; 8 | import com.alibaba.easyretry.common.constant.enums.RetryTaskStatusEnum; 9 | import com.alibaba.easyretry.common.entity.RetryTask; 10 | import com.alibaba.easyretry.common.event.before.AfterSaveBeforeRetryEvent; 11 | import com.alibaba.easyretry.common.event.before.PrepSaveBeforeRetryEvent; 12 | import com.alibaba.easyretry.common.retryer.RetryerInfo; 13 | import com.alibaba.easyretry.common.serializer.ArgSerializerInfo; 14 | import com.alibaba.easyretry.core.process.async.AbstractAsyncPersistenceProcessor; 15 | import com.google.common.collect.Maps; 16 | import lombok.extern.slf4j.Slf4j; 17 | 18 | /** 19 | * @author Created by wuhao on 2021/3/19. 20 | */ 21 | @Slf4j 22 | public abstract class AbstractAsyncPersistenceBeforeRetryProcessor extends 23 | AbstractAsyncPersistenceProcessor { 24 | 25 | protected RetryerInfo retryerInfo; 26 | 27 | // private RetryConfiguration retryConfiguration; 28 | 29 | public AbstractAsyncPersistenceBeforeRetryProcessor( 30 | RetryerInfo retryerInfo) { 31 | this.retryerInfo = retryerInfo; 32 | // this.retryConfiguration = retryConfiguration; 33 | } 34 | 35 | @Override 36 | public void doProcess() { 37 | RetryConfiguration retryConfiguration = retryerInfo.getRetryConfiguration(); 38 | ArgSerializerInfo argSerializerInfo = new ArgSerializerInfo(); 39 | argSerializerInfo.setArgs(retryerInfo.getArgs()); 40 | argSerializerInfo.setExecutorMethodName(retryerInfo.getExecutorMethodName()); 41 | argSerializerInfo.setExecutorName(retryerInfo.getExecutorName()); 42 | String argsStr = retryConfiguration.getRetrySerializerAccess() 43 | .getCurrentGlobalRetrySerializer().serialize(argSerializerInfo); 44 | 45 | RetryTask retryTask = new RetryTask(); 46 | retryTask.setBizId(retryerInfo.getBizId()); 47 | retryTask.setArgsStr(argsStr); 48 | retryTask.setStatus(RetryTaskStatusEnum.INIT); 49 | retryTask.setExecutorMethodName(retryerInfo.getExecutorMethodName()); 50 | retryTask.setExecutorName(retryerInfo.getExecutorName()); 51 | retryTask.setOnFailureMethod(retryerInfo.getOnFailureMethod()); 52 | retryTask.setGmtCreate(new Date()); 53 | retryTask.setGmtModified(new Date()); 54 | 55 | Map extAttrs = Maps.newHashMap(); 56 | if (Objects.nonNull(retryerInfo.getResultPredicate())) { 57 | extAttrs.put("resultPredicateSerializer", 58 | retryConfiguration.getResultPredicateSerializer() 59 | .serialize(retryerInfo.getResultPredicate())); 60 | } 61 | retryTask.setExtAttrs(extAttrs); 62 | 63 | PrepSaveBeforeRetryEvent prepSaveBeforeRetryEvent = new PrepSaveBeforeRetryEvent(retryTask); 64 | retryConfiguration.getRetryEventMulticaster().multicast(prepSaveBeforeRetryEvent); 65 | 66 | retryConfiguration.getRetryTaskAccess().saveRetryTask(retryTask); 67 | 68 | AfterSaveBeforeRetryEvent afterSaveBeforeRetryEvent = new AfterSaveBeforeRetryEvent( 69 | retryTask); 70 | retryConfiguration.getRetryEventMulticaster().multicast(afterSaveBeforeRetryEvent); 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /easy-retry-core/src/main/java/com/alibaba/easyretry/core/process/async/before/ExceptionPersistenceAsyncBeforeRetryProcessor.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.core.process.async.before; 2 | 3 | import java.util.Objects; 4 | 5 | import com.alibaba.easyretry.common.RetryConfiguration; 6 | import com.alibaba.easyretry.common.retryer.RetryerInfo; 7 | 8 | import org.apache.commons.lang3.ClassUtils; 9 | 10 | /** 11 | * @author Created by wuhao on 2021/3/19. 12 | */ 13 | public class ExceptionPersistenceAsyncBeforeRetryProcessor extends 14 | AbstractAsyncPersistenceBeforeRetryProcessor { 15 | 16 | private Throwable throwable; 17 | 18 | public ExceptionPersistenceAsyncBeforeRetryProcessor(Throwable throwable, 19 | RetryerInfo retryerInfo) { 20 | super(retryerInfo); 21 | this.throwable = throwable; 22 | } 23 | 24 | @Override 25 | public boolean needRetry() { 26 | Class onException = retryerInfo.getOnException(); 27 | if (Objects.isNull(onException)) { 28 | return true; 29 | } 30 | return ClassUtils.isAssignable(retryerInfo.getOnException(), throwable.getClass()); 31 | } 32 | 33 | @Override 34 | public R getResult() throws Throwable { 35 | if (retryerInfo.isReThrowException()) { 36 | throw throwable; 37 | } else { 38 | return null; 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /easy-retry-core/src/main/java/com/alibaba/easyretry/core/process/async/before/ResultAsynPersistenceBeforeRetryProcessor.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.core.process.async.before; 2 | 3 | import java.util.Objects; 4 | 5 | import com.alibaba.easyretry.common.AbstractResultPredicate; 6 | import com.alibaba.easyretry.common.retryer.RetryerInfo; 7 | 8 | /** 9 | * @author Created by wuhao on 2021/3/19. 10 | */ 11 | public class ResultAsynPersistenceBeforeRetryProcessor extends 12 | AbstractAsyncPersistenceBeforeRetryProcessor { 13 | 14 | private final R result; 15 | 16 | public ResultAsynPersistenceBeforeRetryProcessor(R result, RetryerInfo retryerInfo) { 17 | super(retryerInfo); 18 | this.result = result; 19 | } 20 | 21 | @Override 22 | public boolean needRetry() { 23 | AbstractResultPredicate easyRetryPredicate = retryerInfo.getResultPredicate(); 24 | if (Objects.nonNull(easyRetryPredicate)) { 25 | return easyRetryPredicate.apply(result); 26 | } else { 27 | return false; 28 | } 29 | } 30 | 31 | @Override 32 | public R getResult() { 33 | return result; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /easy-retry-core/src/main/java/com/alibaba/easyretry/core/process/async/on/AbstractAsyncPersistenceOnRetryProcessor.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.core.process.async.on; 2 | 3 | import com.alibaba.easyretry.common.constant.enums.HandleResultEnum; 4 | import com.alibaba.easyretry.core.context.MaxAttemptsPersistenceRetryContext; 5 | import com.alibaba.easyretry.core.process.async.AbstractAsyncPersistenceProcessor; 6 | import lombok.extern.slf4j.Slf4j; 7 | 8 | /** 9 | * @author Created by wuhao on 2021/3/19. 10 | */ 11 | @Slf4j 12 | public abstract class AbstractAsyncPersistenceOnRetryProcessor extends 13 | AbstractAsyncPersistenceProcessor { 14 | 15 | protected MaxAttemptsPersistenceRetryContext context; 16 | 17 | private HandleResultEnum retryResult; 18 | 19 | 20 | public AbstractAsyncPersistenceOnRetryProcessor(MaxAttemptsPersistenceRetryContext context) { 21 | this.context = context; 22 | } 23 | 24 | @Override 25 | public void process() { 26 | if (!needRetry()) { 27 | retryResult = HandleResultEnum.SUCCESS; 28 | return; 29 | } 30 | doProcess(); 31 | } 32 | 33 | @Override 34 | public void doProcess() { 35 | if (context.getStopStrategy().shouldStop(context)) { 36 | log.error(context.getInvocation() + " will stop"); 37 | retryResult = HandleResultEnum.STOP; 38 | } else { 39 | log.error(context.getInvocation() + " will try later"); 40 | context.getWaitStrategy().backOff(context); 41 | retryResult = HandleResultEnum.FAILURE; 42 | } 43 | } 44 | 45 | public HandleResultEnum getRetryResult() { 46 | return retryResult; 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /easy-retry-core/src/main/java/com/alibaba/easyretry/core/process/async/on/ExceptionPersistenceAsynOnRetryProcessor.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.core.process.async.on; 2 | 3 | import com.alibaba.easyretry.core.context.MaxAttemptsPersistenceRetryContext; 4 | 5 | /** 6 | * @author Created by wuhao on 2021/3/19. 7 | */ 8 | public class ExceptionPersistenceAsynOnRetryProcessor extends 9 | AbstractAsyncPersistenceOnRetryProcessor { 10 | 11 | private final Throwable throwable; 12 | 13 | public ExceptionPersistenceAsynOnRetryProcessor(Throwable throwable, 14 | MaxAttemptsPersistenceRetryContext context) { 15 | super(context); 16 | this.throwable = throwable; 17 | } 18 | 19 | @Override 20 | public boolean needRetry() { 21 | return true; 22 | } 23 | 24 | @Override 25 | public R getResult() { 26 | return null; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /easy-retry-core/src/main/java/com/alibaba/easyretry/core/process/async/on/ResultAsynPersistenceOnRetryProcessor.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.core.process.async.on; 2 | 3 | import com.alibaba.easyretry.common.AbstractResultPredicate; 4 | import com.alibaba.easyretry.core.context.MaxAttemptsPersistenceRetryContext; 5 | 6 | import org.apache.commons.lang3.StringUtils; 7 | 8 | /** 9 | * @author Created by wuhao on 2021/3/19. 10 | */ 11 | public class ResultAsynPersistenceOnRetryProcessor extends 12 | AbstractAsyncPersistenceOnRetryProcessor { 13 | 14 | private R result; 15 | 16 | public ResultAsynPersistenceOnRetryProcessor(R result, 17 | MaxAttemptsPersistenceRetryContext context) { 18 | super(context); 19 | this.result = result; 20 | } 21 | 22 | @Override 23 | public boolean needRetry() { 24 | String resultPredicateSerializerStr = context.getAttribute("resultPredicateSerializer"); 25 | if (StringUtils.isBlank(resultPredicateSerializerStr)) { 26 | return false; 27 | } 28 | AbstractResultPredicate resultPredicate = context.getResultPredicateSerializer() 29 | .deSerialize(resultPredicateSerializerStr); 30 | return resultPredicate.apply(result); 31 | } 32 | 33 | @Override 34 | public R getResult() { 35 | return result; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /easy-retry-core/src/main/java/com/alibaba/easyretry/core/process/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * @author Created by wuhao on 2021/3/19. 3 | */ 4 | package com.alibaba.easyretry.core.process; 5 | -------------------------------------------------------------------------------- /easy-retry-core/src/main/java/com/alibaba/easyretry/core/serializer/FastJsonRetryArgSerializer.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.core.serializer; 2 | 3 | import java.util.stream.Stream; 4 | 5 | import com.alibaba.easyretry.common.serializer.ArgSerializerInfo; 6 | import com.alibaba.easyretry.common.serializer.RetryArgSerializer; 7 | import com.alibaba.fastjson.JSON; 8 | 9 | import org.apache.commons.lang3.ClassUtils; 10 | import org.apache.commons.lang3.StringUtils; 11 | 12 | /** 13 | * 14 | */ 15 | public class FastJsonRetryArgSerializer implements RetryArgSerializer { 16 | 17 | public static final String SPLIT = "||"; 18 | 19 | public static final String INNER_SPLIT = "&&"; 20 | 21 | @Override 22 | public String serialize(ArgSerializerInfo argSerializerInfo) { 23 | StringBuilder sb = new StringBuilder(); 24 | Stream.of(argSerializerInfo.getArgs()).forEach( 25 | (arg) -> sb.append(JSON.toJSONString(arg)).append(INNER_SPLIT) 26 | .append(arg.getClass().getName()).append(SPLIT)); 27 | if (sb.length() >= SPLIT.length()) { 28 | return sb.subSequence(0, sb.length() - SPLIT.length()).toString(); 29 | } else { 30 | return null; 31 | } 32 | } 33 | 34 | @Override 35 | public ArgSerializerInfo deSerialize(String argsStr) { 36 | String[] strs = StringUtils.split(argsStr, SPLIT); 37 | Object[] arg = Stream.of(strs) 38 | .map((str) -> { 39 | String[] inner = str.split(INNER_SPLIT); 40 | try { 41 | return JSON.parseObject(inner[0], ClassUtils.getClass(inner[1])); 42 | } catch (ClassNotFoundException e) { 43 | throw new RuntimeException(e); 44 | } 45 | }) 46 | .toArray(); 47 | ArgSerializerInfo argSerializerInfo = new ArgSerializerInfo(); 48 | argSerializerInfo.setArgs(arg); 49 | return argSerializerInfo; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /easy-retry-core/src/main/java/com/alibaba/easyretry/core/serializer/HessianResultPredicateSerializer.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.core.serializer; 2 | 3 | import com.alibaba.easyretry.common.AbstractResultPredicate; 4 | import com.alibaba.easyretry.common.serializer.ResultPredicateSerializer; 5 | import com.alibaba.easyretry.core.utils.HessianSerializerUtils; 6 | 7 | /** 8 | * @author Created by wuhao on 2021/3/18. 9 | */ 10 | public class HessianResultPredicateSerializer implements ResultPredicateSerializer { 11 | 12 | @Override 13 | public String serialize(AbstractResultPredicate serializeInfo) { 14 | return HessianSerializerUtils.serialize(serializeInfo); 15 | } 16 | 17 | @Override 18 | public AbstractResultPredicate deSerialize(String infoStr) { 19 | return HessianSerializerUtils.deSerialize(infoStr, AbstractResultPredicate.class); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /easy-retry-core/src/main/java/com/alibaba/easyretry/core/serializer/HessianRetryArgSerializer.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.core.serializer; 2 | 3 | /** 4 | * @author Created by wuhao on 2021/2/22. 5 | */ 6 | 7 | import com.alibaba.easyretry.common.serializer.ArgSerializerInfo; 8 | import com.alibaba.easyretry.common.serializer.RetryArgSerializer; 9 | import com.alibaba.easyretry.core.utils.HessianSerializerUtils; 10 | 11 | import lombok.extern.slf4j.Slf4j; 12 | 13 | @Slf4j 14 | public class HessianRetryArgSerializer implements RetryArgSerializer { 15 | 16 | @Override 17 | public String serialize(ArgSerializerInfo argSerializerInfo) { 18 | Object[] args = argSerializerInfo.getArgs(); 19 | if (args.length == 0) { 20 | throw new IllegalStateException("No args found"); 21 | } 22 | return HessianSerializerUtils.serialize(args); 23 | } 24 | 25 | @Override 26 | public ArgSerializerInfo deSerialize(String argStr) { 27 | Object[] result = HessianSerializerUtils.deSerialize(argStr, Object[].class); 28 | ArgSerializerInfo argSerializerInfo = new ArgSerializerInfo(); 29 | argSerializerInfo.setArgs(result); 30 | return argSerializerInfo; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /easy-retry-core/src/main/java/com/alibaba/easyretry/core/strategy/DefaultRetryStrategy.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.core.strategy; 2 | 3 | import java.util.Map; 4 | import java.util.Objects; 5 | import java.util.concurrent.TimeUnit; 6 | 7 | import com.alibaba.easyretry.common.RetryContext; 8 | import com.alibaba.easyretry.common.strategy.StopStrategy; 9 | import com.alibaba.easyretry.common.strategy.WaitStrategy; 10 | import com.alibaba.easyretry.core.context.MaxAttemptsPersistenceRetryContext; 11 | 12 | import com.google.common.collect.Maps; 13 | import lombok.extern.slf4j.Slf4j; 14 | 15 | @Slf4j 16 | public class DefaultRetryStrategy implements StopStrategy, WaitStrategy { 17 | 18 | private static final Long MAX_INTERNAL_TIME = 15 * 60 * 1000L; 19 | private static final Long BASE_INTERNAL_TIME = 5000L; 20 | private final Map internalTimeMap = Maps.newConcurrentMap(); 21 | private final Map retryTimeMap = Maps.newConcurrentMap(); 22 | 23 | @Override 24 | public boolean shouldStop(RetryContext context) { 25 | MaxAttemptsPersistenceRetryContext maxAttemptsPersistenceRetryContext 26 | = (MaxAttemptsPersistenceRetryContext)context; 27 | Integer retryTimes = retryTimeMap.get(context.getId()); 28 | if (Objects.isNull(retryTimes)) { 29 | retryTimes = 1; 30 | } 31 | log.warn( 32 | "shouldStop retryTime is {} id is {} maxRetryTime is {}", 33 | retryTimes, 34 | context.getId(), 35 | maxAttemptsPersistenceRetryContext.getMaxRetryTimes()); 36 | return retryTimes >= maxAttemptsPersistenceRetryContext.getMaxRetryTimes(); 37 | } 38 | 39 | @Override 40 | public boolean shouldWait(RetryContext context) { 41 | MaxAttemptsPersistenceRetryContext maxAttemptsPersistenceRetryContext 42 | = (MaxAttemptsPersistenceRetryContext)context; 43 | internalTimeMap.putIfAbsent(context.getId(), 0L); 44 | Long priority = maxAttemptsPersistenceRetryContext.getNextRetryTime(TimeUnit.MILLISECONDS); 45 | if (Objects.isNull(priority)) { 46 | priority = 0L; 47 | } 48 | return System.currentTimeMillis() < priority; 49 | } 50 | 51 | @Override 52 | public void backOff(RetryContext context) { 53 | MaxAttemptsPersistenceRetryContext maxAttemptsPersistenceRetryContext 54 | = (MaxAttemptsPersistenceRetryContext)context; 55 | 56 | Integer retryTime = retryTimeMap.get(context.getId()); 57 | Long lastInternalTime = internalTimeMap.get(context.getId()); 58 | if (Objects.isNull(retryTime)) { 59 | retryTime = 1; 60 | } 61 | if (Objects.isNull(lastInternalTime)) { 62 | lastInternalTime = 0L; 63 | } 64 | long nextInternalTime = retryTime * (lastInternalTime + BASE_INTERNAL_TIME); 65 | nextInternalTime = Math.min(nextInternalTime, MAX_INTERNAL_TIME); 66 | 67 | internalTimeMap.put(context.getId(), nextInternalTime); 68 | 69 | retryTime++; 70 | retryTimeMap.put(context.getId(), retryTime); 71 | maxAttemptsPersistenceRetryContext 72 | .setNextRetryTime(System.currentTimeMillis() + nextInternalTime, TimeUnit.MILLISECONDS); 73 | log.warn( 74 | "backOff nextInternalTime is {} id is {} retryTime is {}", 75 | nextInternalTime, 76 | context.getId(), 77 | retryTime); 78 | } 79 | 80 | @Override 81 | public void clear(RetryContext context) { 82 | internalTimeMap.remove(context.getId()); 83 | retryTimeMap.remove(context.getId()); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /easy-retry-core/src/main/java/com/alibaba/easyretry/core/utils/HessianSerializerUtils.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.core.utils; 2 | 3 | import java.io.ByteArrayInputStream; 4 | import java.io.ByteArrayOutputStream; 5 | import java.io.IOException; 6 | import java.util.Base64; 7 | 8 | import com.caucho.hessian.io.HessianInput; 9 | import com.caucho.hessian.io.HessianOutput; 10 | 11 | /** 12 | * @author Created by wuhao on 2021/3/18. 13 | */ 14 | public class HessianSerializerUtils { 15 | 16 | public static String serialize(T t) { 17 | try (ByteArrayOutputStream os = new ByteArrayOutputStream()) { 18 | HessianOutput ho = new HessianOutput(os); 19 | ho.writeObject(t); 20 | return Base64.getEncoder().encodeToString(os.toByteArray()); 21 | } catch (IOException e) { 22 | throw new IllegalStateException("HessianSerializationConverter.serialize failed.", e); 23 | } 24 | } 25 | 26 | public static T deSerialize(String str, Class tClass) { 27 | byte[] convertBytes = Base64.getDecoder().decode(str); 28 | try (ByteArrayInputStream is = new ByteArrayInputStream(convertBytes)) { 29 | HessianInput hi = new HessianInput(is); 30 | return (T)hi.readObject(tClass); 31 | } catch (IOException e) { 32 | throw new IllegalStateException("HessianSerializationConverter.deSerialize failed.", e); 33 | } 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /easy-retry-core/src/main/java/com/alibaba/easyretry/core/utils/LogUtils.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.core.utils; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | 6 | /** 7 | * @author Created by wuhao on 2020/11/13. 8 | */ 9 | public class LogUtils { 10 | 11 | public static final Logger CONSISTENCY_LOGGER = LoggerFactory.getLogger("aRetryConsistency"); 12 | } 13 | -------------------------------------------------------------------------------- /easy-retry-core/src/main/java/com/alibaba/easyretry/core/utils/PrintUtils.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.core.utils; 2 | 3 | import com.alibaba.easyretry.common.RetryContext; 4 | 5 | import lombok.extern.slf4j.Slf4j; 6 | 7 | /** 8 | * @author Created by wuhao on 2020/11/14. 9 | */ 10 | @Slf4j 11 | public class PrintUtils { 12 | 13 | public static void monitorInfo(String action, RetryContext context) { 14 | monitorInfo(action, context, ""); 15 | } 16 | 17 | public static void monitorInfo(String action, RetryContext context, String extraInfo) { 18 | log.info(action + " arg is {} task id is {} " + extraInfo, context.getInvocation(), 19 | context.getId()); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /easy-retry-core/src/test/java/com/alibaba/easyretry/core/utils/TestClass.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.core.utils; 2 | 3 | class TestClass { 4 | 5 | public void say() { 6 | System.out.println("1"); 7 | } 8 | 9 | } 10 | -------------------------------------------------------------------------------- /easy-retry-extensions/easy-retry-guava-extension/pom.xml: -------------------------------------------------------------------------------- 1 | 4 | 4.0.0 5 | 6 | com.alibaba 7 | easy-retry-extensions 8 | ${revision} 9 | ../pom.xml 10 | 11 | 12 | easy-retry-guava-extension 13 | 14 | easy-retry-guava-extension 15 | easy-retry-guava-extension 16 | 17 | 18 | 19 | ${project.groupId} 20 | easy-retry-common 21 | 22 | 23 | 24 | ${project.groupId} 25 | easy-retry-core 26 | 27 | 28 | com.google.guava 29 | guava 30 | 31 | 32 | 33 | com.github.rholder 34 | guava-retrying 35 | 2.0.0 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /easy-retry-extensions/easy-retry-guava-extension/src/main/java/com/alibaba/easyretry/extension/guava/GuavaRetrySyncExecutor.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.extension.guava; 2 | 3 | import java.util.Objects; 4 | import java.util.concurrent.TimeUnit; 5 | 6 | import com.alibaba.easyretry.common.AbstractResultPredicate; 7 | import com.alibaba.easyretry.common.AbstractRetrySyncExecutor; 8 | import com.alibaba.easyretry.common.SCallable; 9 | import com.alibaba.easyretry.common.retryer.RetryerInfo; 10 | import com.github.rholder.retry.Retryer; 11 | import com.github.rholder.retry.RetryerBuilder; 12 | import com.github.rholder.retry.StopStrategies; 13 | import com.github.rholder.retry.WaitStrategies; 14 | 15 | public class GuavaRetrySyncExecutor extends AbstractRetrySyncExecutor { 16 | 17 | private static final long WAIT_TIME = 1000L; 18 | 19 | @Override 20 | public V call(SCallable callable) throws Throwable { 21 | 22 | RetryerInfo retryerInfo = getRetryerInfo(); 23 | Class onException = Throwable.class; 24 | if (Objects.nonNull(retryerInfo.getOnException())) { 25 | onException = retryerInfo.getOnException(); 26 | } 27 | 28 | RetryerBuilder retryerBuilder = RetryerBuilder.newBuilder() 29 | .retryIfExceptionOfType(onException) 30 | .withStopStrategy(StopStrategies.stopAfterAttempt(retryerInfo.getRetryConfiguration().getMaxRetryTimes())) 31 | .withWaitStrategy(WaitStrategies.fixedWait(WAIT_TIME, TimeUnit.MILLISECONDS)); 32 | 33 | AbstractResultPredicate resultPredicate = retryerInfo.getResultPredicate(); 34 | if (Objects.nonNull(resultPredicate)) { 35 | retryerBuilder.retryIfResult(resultPredicate::apply); 36 | } 37 | 38 | Retryer retryer = retryerBuilder.build(); 39 | return retryer.call(() -> { 40 | try { 41 | return callable.call(); 42 | } catch (Throwable t) { 43 | throw new Exception(t); 44 | } 45 | }); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /easy-retry-extensions/easy-retry-guava-extension/src/main/java/com/alibaba/easyretry/extension/guava/package-info.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.extension.guava; 2 | -------------------------------------------------------------------------------- /easy-retry-extensions/easy-retry-mybatis-extension/pom.xml: -------------------------------------------------------------------------------- 1 | 4 | 4.0.0 5 | 6 | com.alibaba 7 | easy-retry-extensions 8 | ${revision} 9 | ../pom.xml 10 | 11 | 12 | easy-retry-mybatis-extension 13 | easy-retry-mybatis-extension 14 | easy-retry-mybatis-extension 15 | 16 | 3.5.6 17 | 1.4.200 18 | 19 | 20 | 21 | 22 | com.alibaba 23 | easy-retry-common 24 | 25 | 26 | 27 | org.mybatis 28 | mybatis 29 | ${mybatis.version} 30 | 31 | 32 | 33 | com.google.guava 34 | guava 35 | 36 | 37 | 38 | com.alibaba 39 | fastjson 40 | 41 | 42 | 43 | com.h2database 44 | h2 45 | ${h2.version} 46 | test 47 | 48 | 49 | 50 | com.zaxxer 51 | HikariCP 52 | 4.0.3 53 | test 54 | 55 | 56 | 57 | org.slf4j 58 | slf4j-api 59 | test 60 | 61 | 62 | 63 | ch.qos.logback 64 | logback-classic 65 | 1.2.3 66 | test 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /easy-retry-extensions/easy-retry-mybatis-extension/src/main/java/com/alibaba/easyretry/extension/mybatis/access/MybatisRetryTaskAccess.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.extension.mybatis.access; 2 | 3 | import java.util.List; 4 | import java.util.Map; 5 | import java.util.Objects; 6 | import java.util.stream.Collectors; 7 | 8 | import com.alibaba.easyretry.common.access.RetryTaskAccess; 9 | import com.alibaba.easyretry.common.constant.enums.RetryTaskStatusEnum; 10 | import com.alibaba.easyretry.common.entity.RetryTask; 11 | import com.alibaba.easyretry.extension.mybatis.common.utils.HostUtils; 12 | import com.alibaba.easyretry.extension.mybatis.dao.RetryTaskDAO; 13 | import com.alibaba.easyretry.extension.mybatis.po.RetryTaskPO; 14 | import com.alibaba.easyretry.extension.mybatis.query.RetryTaskQuery; 15 | import com.alibaba.fastjson.JSON; 16 | import com.alibaba.fastjson.TypeReference; 17 | 18 | import com.google.common.collect.Lists; 19 | import com.google.common.collect.Maps; 20 | import lombok.AllArgsConstructor; 21 | 22 | /** 23 | * @author Created by wuhao on 2020/11/8. 24 | */ 25 | @AllArgsConstructor 26 | public class MybatisRetryTaskAccess implements RetryTaskAccess { 27 | 28 | private final RetryTaskDAO retryTaskDAO; 29 | 30 | @Override 31 | public boolean saveRetryTask(RetryTask retryTask) { 32 | RetryTaskPO retryTaskPO = covert(retryTask); 33 | return retryTaskDAO.saveRetryTask(retryTaskPO); 34 | } 35 | 36 | @Override 37 | public boolean handlingRetryTask(RetryTask retryTask) { 38 | return updateRetryTaskStatus(retryTask, RetryTaskStatusEnum.HANDLING); 39 | } 40 | 41 | @Override 42 | public boolean finishRetryTask(RetryTask retryTask) { 43 | RetryTaskPO retryTaskPO = new RetryTaskPO().setId(retryTask.getId()); 44 | return retryTaskDAO.deleteRetryTask(retryTaskPO); 45 | // return updateRetryTaskStatus(retryTask, RetryTaskStatusEnum.FINISH); 46 | } 47 | 48 | @Override 49 | public boolean stopRetryTask(RetryTask retryTask) { 50 | return updateRetryTaskStatus(retryTask, RetryTaskStatusEnum.ERROR); 51 | } 52 | 53 | private boolean updateRetryTaskStatus(RetryTask retryTask, RetryTaskStatusEnum status) { 54 | RetryTaskPO retryTaskPO = new RetryTaskPO(); 55 | retryTaskPO.setId(retryTask.getId()); 56 | retryTaskPO.setRetryStatus(status.getCode()); 57 | return retryTaskDAO.updateRetryTask(retryTaskPO); 58 | } 59 | 60 | @Override 61 | public List listAvailableTasks(Long lastId) { 62 | RetryTaskQuery retryTaskQuery = new RetryTaskQuery(); 63 | retryTaskQuery.setRetryStatus( 64 | Lists.newArrayList( 65 | RetryTaskStatusEnum.INIT.getCode(), RetryTaskStatusEnum.HANDLING.getCode())); 66 | retryTaskQuery.setLastId(lastId); 67 | retryTaskQuery.setSharding(HostUtils.getHostIP()); 68 | List retryTasks = retryTaskDAO.listRetryTask(retryTaskQuery); 69 | return convert(retryTasks); 70 | } 71 | 72 | private List convert(List retryTasks) { 73 | return retryTasks.stream().map(this::convert).collect(Collectors.toList()); 74 | } 75 | 76 | private RetryTask convert(RetryTaskPO retryTaskPO) { 77 | RetryTask retryTask = new RetryTask(); 78 | retryTask.setId(retryTaskPO.getId()); 79 | retryTask.setStatus(RetryTaskStatusEnum.fromCode(retryTaskPO.getRetryStatus())); 80 | retryTask.setArgsStr(retryTaskPO.getArgsStr()); 81 | retryTask.setGmtCreate(retryTaskPO.getGmtCreate()); 82 | retryTask.setGmtModified(retryTaskPO.getGmtModified()); 83 | retryTask.setExecutorName(retryTaskPO.getExecutorName()); 84 | retryTask.setExecutorMethodName(retryTaskPO.getExecutorMethodName()); 85 | retryTask.setBizId(retryTaskPO.getBizId()); 86 | retryTask.setExtAttrs(JSON.parseObject(retryTaskPO.getExtAttrs(), 87 | new TypeReference>() {})); 88 | return retryTask; 89 | } 90 | 91 | private RetryTaskPO covert(RetryTask retryTask) { 92 | RetryTaskPO retryTaskPO = new RetryTaskPO(); 93 | retryTaskPO.setId(retryTask.getId()); 94 | retryTaskPO.setSharding(HostUtils.getHostIP()); 95 | retryTaskPO.setBizId(retryTask.getBizId()); 96 | retryTaskPO.setExecutorName(retryTask.getExecutorName()); 97 | retryTaskPO.setExecutorMethodName(retryTask.getExecutorMethodName()); 98 | 99 | Map extAttrs = retryTask.getExtAttrs(); 100 | if (Objects.isNull(extAttrs)) { 101 | extAttrs = Maps.newHashMap(); 102 | } 103 | extAttrs.put("onFailureMethod", retryTask.getOnFailureMethod()); 104 | retryTaskPO.setExtAttrs(JSON.toJSONString(extAttrs)); 105 | retryTaskPO.setRetryStatus(retryTask.getStatus().getCode()); 106 | retryTaskPO.setArgsStr(retryTask.getArgsStr()); 107 | retryTaskPO.setGmtCreate(retryTask.getGmtCreate()); 108 | retryTaskPO.setGmtModified(retryTask.getGmtModified()); 109 | return retryTaskPO; 110 | } 111 | 112 | } 113 | -------------------------------------------------------------------------------- /easy-retry-extensions/easy-retry-mybatis-extension/src/main/java/com/alibaba/easyretry/extension/mybatis/common/utils/HostUtils.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.extension.mybatis.common.utils; 2 | 3 | import java.net.InetAddress; 4 | import java.net.UnknownHostException; 5 | import java.util.Objects; 6 | 7 | public class HostUtils { 8 | 9 | private static final String IP; 10 | 11 | static { 12 | InetAddress address = null; 13 | try { 14 | address = InetAddress.getLocalHost(); 15 | } catch (UnknownHostException e) { 16 | // do noting 17 | } 18 | if (Objects.isNull(address)) { 19 | IP = "UNKNOW-IP"; 20 | } else { 21 | IP = address.getHostAddress(); 22 | } 23 | } 24 | 25 | public static String getHostIP() { 26 | return IP; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /easy-retry-extensions/easy-retry-mybatis-extension/src/main/java/com/alibaba/easyretry/extension/mybatis/dao/BaseDAOSupport.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.extension.mybatis.dao; 2 | 3 | import java.util.Objects; 4 | import java.util.function.Function; 5 | 6 | import org.apache.ibatis.session.SqlSession; 7 | import org.apache.ibatis.session.SqlSessionFactory; 8 | 9 | /** 10 | * @author wuhao 11 | */ 12 | public abstract class BaseDAOSupport { 13 | 14 | private final SqlSessionFactory sqlSessionFactory; 15 | 16 | public BaseDAOSupport(SqlSessionFactory sqlSessionFactory) { 17 | this.sqlSessionFactory = sqlSessionFactory; 18 | } 19 | 20 | protected T execute(Function function) { 21 | Objects.requireNonNull(sqlSessionFactory, "require sqlSessionFactory non null"); 22 | try (final SqlSession session = sqlSessionFactory.openSession(false)) { 23 | return function.apply(session); 24 | } 25 | } 26 | 27 | protected T execute(Function function, boolean autoCommit) { 28 | Objects.requireNonNull(sqlSessionFactory, "require sqlSessionFactory non null"); 29 | try (final SqlSession session = sqlSessionFactory.openSession(autoCommit)) { 30 | return function.apply(session); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /easy-retry-extensions/easy-retry-mybatis-extension/src/main/java/com/alibaba/easyretry/extension/mybatis/dao/RetryTaskDAO.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.extension.mybatis.dao; 2 | 3 | import java.util.List; 4 | 5 | import com.alibaba.easyretry.extension.mybatis.po.RetryTaskPO; 6 | import com.alibaba.easyretry.extension.mybatis.query.RetryTaskQuery; 7 | 8 | /** 9 | * @author Created by wuhao on 2020/11/8. 10 | */ 11 | public interface RetryTaskDAO { 12 | 13 | boolean saveRetryTask(RetryTaskPO retryTaskPO); 14 | 15 | List listRetryTask(RetryTaskQuery retryTaskQuery); 16 | 17 | boolean updateRetryTask(RetryTaskPO retryTaskPO); 18 | 19 | boolean deleteRetryTask(RetryTaskPO retryTaskPO); 20 | } 21 | -------------------------------------------------------------------------------- /easy-retry-extensions/easy-retry-mybatis-extension/src/main/java/com/alibaba/easyretry/extension/mybatis/dao/RetryTaskDAOImpl.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.extension.mybatis.dao; 2 | 3 | import java.util.List; 4 | 5 | import com.alibaba.easyretry.extension.mybatis.po.RetryTaskPO; 6 | import com.alibaba.easyretry.extension.mybatis.query.RetryTaskQuery; 7 | 8 | import java.util.List; 9 | 10 | import org.apache.ibatis.session.SqlSessionFactory; 11 | 12 | /** 13 | * @author Created by wuhao on 2020/11/8. 14 | */ 15 | public class RetryTaskDAOImpl extends BaseDAOSupport implements RetryTaskDAO { 16 | 17 | public RetryTaskDAOImpl(SqlSessionFactory sqlSessionFactory) { 18 | super(sqlSessionFactory); 19 | } 20 | 21 | @Override 22 | public boolean saveRetryTask(RetryTaskPO retryTaskPO) { 23 | return execute( 24 | sqlSession -> 25 | sqlSession.insert("com.alibaba.easyretry.extension.mybatis.dao.RetryTaskDAO.saveRetryTask", retryTaskPO) > 0 26 | , true); 27 | } 28 | 29 | @Override 30 | public List listRetryTask(RetryTaskQuery retryTaskQuery) { 31 | return execute(sqlSession -> 32 | sqlSession.selectList( 33 | "com.alibaba.easyretry.extension.mybatis.dao.RetryTaskDAO.listRetryTask", 34 | retryTaskQuery) 35 | ); 36 | } 37 | 38 | @Override 39 | public boolean updateRetryTask(RetryTaskPO retryTaskPO) { 40 | return execute(sqlSession -> 41 | sqlSession.update( 42 | "com.alibaba.easyretry.extension.mybatis.dao.RetryTaskDAO.updateRetryTask", 43 | retryTaskPO) 44 | > 0 45 | , true); 46 | } 47 | 48 | @Override 49 | public boolean deleteRetryTask(RetryTaskPO retryTaskPO) { 50 | return execute(sqlSession -> 51 | sqlSession.delete( 52 | "com.alibaba.easyretry.extension.mybatis.dao.RetryTaskDAO.deleteRetryTask", 53 | retryTaskPO) 54 | > 0 55 | , true); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /easy-retry-extensions/easy-retry-mybatis-extension/src/main/java/com/alibaba/easyretry/extension/mybatis/po/RetryTaskPO.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.extension.mybatis.po; 2 | 3 | import java.util.Date; 4 | 5 | import com.alibaba.easyretry.common.constant.enums.RetryTaskStatusEnum; 6 | 7 | import lombok.Data; 8 | import lombok.experimental.Accessors; 9 | 10 | /** 11 | * @author Created by wuhao on 2020/11/8. 12 | */ 13 | @Data 14 | @Accessors(chain = true) 15 | public class RetryTaskPO { 16 | 17 | /** 18 | * 主键id 19 | */ 20 | private Long id; 21 | 22 | /** 23 | * 分片id 24 | */ 25 | private String sharding; 26 | 27 | /** 28 | * 业务信息 29 | */ 30 | private String bizId; 31 | 32 | /** 33 | * 执行者名称 34 | */ 35 | private String executorName; 36 | 37 | /** 38 | * 执行者方法 39 | */ 40 | private String executorMethodName; 41 | 42 | /** 43 | * @see RetryTaskStatusEnum 44 | */ 45 | private Integer retryStatus; 46 | 47 | private String argsStr; 48 | 49 | private Date gmtCreate; 50 | 51 | private Date gmtModified; 52 | 53 | private String extAttrs; 54 | } 55 | -------------------------------------------------------------------------------- /easy-retry-extensions/easy-retry-mybatis-extension/src/main/java/com/alibaba/easyretry/extension/mybatis/query/RetryTaskQuery.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.extension.mybatis.query; 2 | 3 | import java.util.List; 4 | 5 | import lombok.Data; 6 | import lombok.experimental.Accessors; 7 | 8 | /** 9 | * @author Created by wuhao on 2020/11/8. 10 | */ 11 | @Data 12 | @Accessors(chain = true) 13 | public class RetryTaskQuery { 14 | 15 | private Long lastId; 16 | 17 | private List retryStatus; 18 | 19 | private String sharding; 20 | } 21 | -------------------------------------------------------------------------------- /easy-retry-extensions/easy-retry-mybatis-extension/src/main/resources/dal/easyretry/easy-mybatis-config.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /easy-retry-extensions/easy-retry-mybatis-extension/src/main/resources/dal/easyretry/mapper/easy-retry-task-mapper.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | `id` 21 | , 22 | `sharding`, 23 | `biz_id`, 24 | `executor_name`, 25 | `executor_method_name`, 26 | `retry_status`, 27 | `args_str`, 28 | `gmt_create`, 29 | `gmt_modified`, 30 | `ext_attrs` 31 | 32 | 33 | 34 | INSERT INTO easy_retry_task (`id`, 35 | `sharding`, 36 | `biz_id`, 37 | `executor_name`, 38 | `executor_method_name`, 39 | `retry_status`, 40 | `args_str`, 41 | `gmt_create`, 42 | `gmt_modified`, 43 | `ext_attrs`) 44 | VALUES (#{id}, 45 | #{sharding}, 46 | #{bizId}, 47 | #{executorName}, 48 | #{executorMethodName}, 49 | #{retryStatus}, 50 | #{argsStr}, 51 | #{gmtCreate}, 52 | #{gmtModified}, 53 | #{extAttrs}) 54 | 55 | 56 | 78 | 79 | 81 | UPDATE easy_retry_task 82 | SET 83 | gmt_modified = now() 84 | 85 | ,retry_status = #{retryStatus} 86 | 87 | WHERE 88 | id=#{id} 89 | 90 | 91 | 93 | DELETE 94 | FROM easy_retry_task 95 | WHERE id = #{id} 96 | 97 | 98 | -------------------------------------------------------------------------------- /easy-retry-extensions/easy-retry-mybatis-extension/src/test/java/com/alibaba/easyretry/extension/mybatis/DbConfig.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.extension.mybatis; 2 | 3 | import javax.sql.DataSource; 4 | 5 | import com.zaxxer.hikari.HikariConfig; 6 | import com.zaxxer.hikari.HikariDataSource; 7 | import lombok.Getter; 8 | import org.junit.jupiter.api.Assertions; 9 | import org.junit.jupiter.api.Test; 10 | 11 | public final class DbConfig { 12 | 13 | @Getter 14 | private static final DataSource dataSource; 15 | 16 | static { 17 | String url = "jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;INIT=runscript from 'classpath:/task.sql'"; 18 | HikariConfig config = new HikariConfig(); 19 | config.setJdbcUrl(url); 20 | config.setUsername("sa"); 21 | config.setDriverClassName("org.h2.Driver"); 22 | config.setPassword("sa"); 23 | config.addDataSourceProperty("cachePrepStmts", "true"); 24 | config.addDataSourceProperty("prepStmtCacheSize", "250"); 25 | config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048"); 26 | dataSource = new HikariDataSource(config); 27 | } 28 | 29 | @Test 30 | void test() { 31 | Assertions.assertNotNull(DbConfig.getDataSource()); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /easy-retry-extensions/easy-retry-mybatis-extension/src/test/java/com/alibaba/easyretry/extension/mybatis/MyBatisConfig.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.extension.mybatis; 2 | 3 | import java.io.IOException; 4 | 5 | import lombok.Getter; 6 | import org.apache.ibatis.builder.xml.XMLConfigBuilder; 7 | import org.apache.ibatis.io.Resources; 8 | import org.apache.ibatis.logging.slf4j.Slf4jImpl; 9 | import org.apache.ibatis.mapping.Environment; 10 | import org.apache.ibatis.session.Configuration; 11 | import org.apache.ibatis.session.SqlSessionFactory; 12 | import org.apache.ibatis.session.SqlSessionFactoryBuilder; 13 | import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory; 14 | import org.junit.jupiter.api.Assertions; 15 | import org.junit.jupiter.api.Test; 16 | 17 | public final class MyBatisConfig { 18 | 19 | @Getter 20 | private static final SqlSessionFactory factory; 21 | 22 | static { 23 | String resource = "dal/easyretry/easy-mybatis-config.xml"; 24 | Configuration parse; 25 | try { 26 | XMLConfigBuilder parser = new XMLConfigBuilder(Resources.getResourceAsStream(resource), 27 | null, null); 28 | parse = parser.parse(); 29 | } catch (IOException e) { 30 | throw new RuntimeException(e); 31 | } 32 | final Environment development = new Environment("development", 33 | new JdbcTransactionFactory(), DbConfig.getDataSource()); 34 | parse.setEnvironment(development); 35 | parse.setLogImpl(Slf4jImpl.class); 36 | factory = new SqlSessionFactoryBuilder().build(parse); 37 | } 38 | 39 | @Test 40 | void testNotNull() { 41 | Assertions.assertNotNull(MyBatisConfig.getFactory()); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /easy-retry-extensions/easy-retry-mybatis-extension/src/test/java/com/alibaba/easyretry/extension/mybatis/access/MybatisRetryTaskAccessTest.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.extension.mybatis.access; 2 | 3 | import java.util.Date; 4 | import java.util.List; 5 | import java.util.Objects; 6 | 7 | import org.junit.jupiter.api.Assertions; 8 | import org.junit.jupiter.api.BeforeAll; 9 | import org.junit.jupiter.api.MethodOrderer; 10 | import org.junit.jupiter.api.Order; 11 | import org.junit.jupiter.api.Test; 12 | import org.junit.jupiter.api.TestMethodOrder; 13 | 14 | import com.alibaba.easyretry.common.constant.enums.RetryTaskStatusEnum; 15 | import com.alibaba.easyretry.common.entity.RetryTask; 16 | import com.alibaba.easyretry.extension.mybatis.MyBatisConfig; 17 | import com.alibaba.easyretry.extension.mybatis.dao.RetryTaskDAOImpl; 18 | 19 | @TestMethodOrder(MethodOrderer.OrderAnnotation.class) 20 | class MybatisRetryTaskAccessTest { 21 | 22 | private static final MybatisRetryTaskAccess ACCESS = new MybatisRetryTaskAccess( 23 | new RetryTaskDAOImpl( 24 | MyBatisConfig.getFactory())); 25 | 26 | private static RetryTask task; 27 | 28 | @BeforeAll 29 | static void prepare() { 30 | RetryTask retryTask = new RetryTask(); 31 | retryTask.setId(2L); 32 | retryTask.setGmtCreate(new Date()); 33 | retryTask.setGmtModified(new Date()); 34 | retryTask.setBizId("2"); 35 | retryTask.setStatus(RetryTaskStatusEnum.INIT); 36 | task = retryTask; 37 | } 38 | 39 | @Test 40 | @Order(1) 41 | void saveTask() { 42 | Assertions.assertTrue(ACCESS.saveRetryTask(task)); 43 | } 44 | 45 | @Test 46 | @Order(2) 47 | void handle() { 48 | // ACCESS.saveRetryTask(task); 49 | Assertions.assertTrue(ACCESS.handlingRetryTask(task)); 50 | List retryTasks = ACCESS.listAvailableTasks(1L); 51 | Assertions.assertTrue(Objects.nonNull(retryTasks) && !retryTasks.isEmpty()); 52 | Assertions.assertEquals(retryTasks.get(0).getStatus(), RetryTaskStatusEnum.HANDLING); 53 | } 54 | 55 | @Test 56 | @Order(3) 57 | void stop() { 58 | // ACCESS.saveRetryTask(task); 59 | boolean b = ACCESS.stopRetryTask(task); 60 | Assertions.assertTrue(b); 61 | List retryTasks = ACCESS.listAvailableTasks(1L); 62 | Assertions.assertTrue(Objects.isNull(retryTasks) || retryTasks.isEmpty()); 63 | } 64 | 65 | @Test 66 | @Order(4) 67 | void finish(){ 68 | // ACCESS.saveRetryTask(task); 69 | Assertions.assertTrue(ACCESS.finishRetryTask(task)); 70 | List retryTasks = ACCESS.listAvailableTasks(1L); 71 | Assertions.assertTrue(Objects.isNull(retryTasks) || retryTasks.isEmpty()); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /easy-retry-extensions/easy-retry-mybatis-extension/src/test/java/com/alibaba/easyretry/extension/mybatis/common/utils/HostUtilsTest.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.extension.mybatis.common.utils; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import static org.junit.jupiter.api.Assertions.assertNotNull; 6 | 7 | class HostUtilsTest { 8 | 9 | @Test 10 | void getHostIP() { 11 | String hostIP = HostUtils.getHostIP(); 12 | assertNotNull(hostIP); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /easy-retry-extensions/easy-retry-mybatis-extension/src/test/java/com/alibaba/easyretry/extension/mybatis/dao/RetryTaskDAOImplTest.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.extension.mybatis.dao; 2 | 3 | import java.util.Collections; 4 | import java.util.Date; 5 | import java.util.List; 6 | import java.util.Objects; 7 | 8 | import org.junit.jupiter.api.Assertions; 9 | import org.junit.jupiter.api.BeforeAll; 10 | import org.junit.jupiter.api.Order; 11 | import org.junit.jupiter.api.Test; 12 | 13 | import com.alibaba.easyretry.common.constant.enums.RetryTaskStatusEnum; 14 | import com.alibaba.easyretry.extension.mybatis.MyBatisConfig; 15 | import com.alibaba.easyretry.extension.mybatis.po.RetryTaskPO; 16 | import com.alibaba.easyretry.extension.mybatis.query.RetryTaskQuery; 17 | 18 | class RetryTaskDAOImplTest { 19 | 20 | private static RetryTaskDAO retryTaskDAO; 21 | 22 | @BeforeAll 23 | static void prepare() { 24 | retryTaskDAO = new RetryTaskDAOImpl(MyBatisConfig.getFactory()); 25 | } 26 | 27 | @Test 28 | @Order(1) 29 | void saveTask() { 30 | final RetryTaskPO retryTaskPO = new RetryTaskPO() 31 | .setId(1L) 32 | .setGmtCreate(new Date()) 33 | .setBizId("1") 34 | .setRetryStatus(RetryTaskStatusEnum.HANDLING.getCode()) 35 | .setGmtModified(new Date()); 36 | 37 | final boolean result = retryTaskDAO.saveRetryTask(retryTaskPO); 38 | Assertions.assertTrue(result); 39 | } 40 | 41 | @Test 42 | @Order(2) 43 | void listRetryTask() { 44 | final RetryTaskPO retryTaskPO = new RetryTaskPO() 45 | .setId(2L) 46 | .setGmtCreate(new Date()) 47 | .setBizId("2") 48 | .setRetryStatus(RetryTaskStatusEnum.HANDLING.getCode()) 49 | .setGmtModified(new Date()); 50 | 51 | retryTaskDAO.saveRetryTask(retryTaskPO); 52 | final RetryTaskQuery retryTaskQuery = new RetryTaskQuery() 53 | .setRetryStatus(Collections.singletonList(RetryTaskStatusEnum.HANDLING.getCode())); 54 | List retryTaskPOS = retryTaskDAO.listRetryTask(retryTaskQuery); 55 | System.out.println(retryTaskPOS); 56 | Assertions.assertTrue(!retryTaskPOS.isEmpty()); 57 | Assertions.assertTrue(Objects.nonNull(retryTaskPOS)); 58 | // Assertions.assertTrue(Objects.nonNull(retryTaskPOS) && !retryTaskPOS.isEmpty()); 59 | } 60 | 61 | @Test 62 | @Order(3) 63 | void updateRetryTask() { 64 | //final RetryTaskPO retryTaskPO = new RetryTaskPO() 65 | // .setId(1L) 66 | // .setBizId("1") 67 | // .setRetryStatus(RetryTaskStatusEnum.FINISH.getCode()) 68 | // .setGmtModified(new Date()); 69 | // 70 | //boolean b = retryTaskDAO.updateRetryTask(retryTaskPO); 71 | //Assertions.assertTrue(b); 72 | // 73 | //final RetryTaskQuery retryTaskQuery = new RetryTaskQuery() 74 | // .setRetryStatus(Collections.singletonList(RetryTaskStatusEnum.FINISH.getCode())); 75 | //List retryTaskPOS = retryTaskDAO.listRetryTask(retryTaskQuery); 76 | //System.out.println(retryTaskPOS); 77 | //Assertions.assertTrue(Objects.nonNull(retryTaskPOS) && !retryTaskPOS.isEmpty()); 78 | } 79 | 80 | @Test 81 | @Order(4) 82 | void deleteRetryTask() { 83 | final RetryTaskPO retryTaskPO = new RetryTaskPO() 84 | .setId(3L) 85 | .setGmtCreate(new Date()) 86 | .setBizId("3") 87 | .setRetryStatus(RetryTaskStatusEnum.HANDLING.getCode()) 88 | .setGmtModified(new Date()); 89 | 90 | retryTaskDAO.saveRetryTask(retryTaskPO); 91 | boolean b = retryTaskDAO.deleteRetryTask(retryTaskPO); 92 | Assertions.assertTrue(b); 93 | 94 | final RetryTaskQuery retryTaskQuery = new RetryTaskQuery() 95 | .setRetryStatus(Collections.singletonList(RetryTaskStatusEnum.FINISH.getCode())); 96 | List retryTaskPOS = retryTaskDAO.listRetryTask(retryTaskQuery); 97 | System.out.println(retryTaskPOS); 98 | Assertions.assertTrue(Objects.isNull(retryTaskPOS) || retryTaskPOS.isEmpty()); 99 | } 100 | 101 | } 102 | -------------------------------------------------------------------------------- /easy-retry-extensions/easy-retry-mybatis-extension/src/test/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /easy-retry-extensions/easy-retry-mybatis-extension/src/test/resources/task.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE IF NOT EXISTS easy_retry_task ( 2 | id bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '主键' PRIMARY KEY, 3 | gmt_create datetime NOT NULL COMMENT '创建时间', 4 | gmt_modified datetime NOT NULL COMMENT '修改时间', 5 | sharding varchar(64) NULL COMMENT '数据库分片字段', 6 | biz_id varchar(64) NULL COMMENT '业务id', 7 | executor_name varchar(512) NULL COMMENT '执行名称', 8 | executor_method_name varchar(512) NULL COMMENT '执行方法名称', 9 | retry_status tinyint NOT NULL COMMENT '重试状态', 10 | args_str varchar(3000) NULL COMMENT '执行方法参数', 11 | ext_attrs varchar(3000) NULL COMMENT '扩展字段' 12 | ); 13 | -------------------------------------------------------------------------------- /easy-retry-extensions/easy-retry-spring-extension/pom.xml: -------------------------------------------------------------------------------- 1 | 4 | 4.0.0 5 | 6 | com.alibaba 7 | easy-retry-extensions 8 | ${revision} 9 | ../pom.xml 10 | 11 | 12 | easy-retry-spring-extension 13 | 14 | easy-retry-spring-extension 15 | easy-retry-spring-extension 16 | 17 | 18 | 19 | ${project.groupId} 20 | easy-retry-common 21 | 22 | 23 | 24 | ${project.groupId} 25 | easy-retry-core 26 | 27 | 28 | com.google.guava 29 | guava 30 | 31 | 32 | 33 | org.springframework 34 | spring-context 35 | 5.1.12.RELEASE 36 | 37 | 38 | 39 | org.springframework 40 | spring-core 41 | 5.1.12.RELEASE 42 | 43 | 44 | 45 | org.aspectj 46 | aspectjweaver 47 | 1.9.5 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /easy-retry-extensions/easy-retry-spring-extension/src/main/java/com/alibaba/easyretry/extension/spring/RetryListenerInitialize.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.extension.spring; 2 | 3 | import java.util.Map; 4 | 5 | import com.alibaba.easyretry.common.event.RetryEventMulticaster; 6 | import com.alibaba.easyretry.common.event.RetryListener; 7 | 8 | import lombok.Setter; 9 | import org.apache.commons.collections4.MapUtils; 10 | import org.springframework.beans.BeansException; 11 | import org.springframework.beans.factory.SmartInitializingSingleton; 12 | import org.springframework.context.ApplicationContext; 13 | import org.springframework.context.ApplicationContextAware; 14 | 15 | /** 16 | * @author Created by wuhao on 2021/4/9. 17 | */ 18 | public class RetryListenerInitialize implements SmartInitializingSingleton, ApplicationContextAware { 19 | 20 | @Setter 21 | private RetryEventMulticaster retryEventMulticaster; 22 | 23 | private ApplicationContext applicationContext; 24 | 25 | @Override 26 | public void afterSingletonsInstantiated() { 27 | Map retryListenerMap = applicationContext.getBeansOfType(RetryListener.class); 28 | MapUtils.emptyIfNull(retryListenerMap).values().forEach( 29 | (retryListener) -> retryEventMulticaster.register(retryListener)); 30 | } 31 | 32 | @Override 33 | public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { 34 | this.applicationContext = applicationContext; 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /easy-retry-extensions/easy-retry-spring-extension/src/main/java/com/alibaba/easyretry/extension/spring/SPELParamPredicate.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.extension.spring; 2 | 3 | import java.lang.reflect.Method; 4 | 5 | import com.alibaba.easyretry.common.EasyRetryPredicate; 6 | 7 | import lombok.Data; 8 | import org.apache.commons.lang3.ArrayUtils; 9 | import org.springframework.core.DefaultParameterNameDiscoverer; 10 | import org.springframework.expression.ExpressionParser; 11 | import org.springframework.expression.spel.standard.SpelExpressionParser; 12 | import org.springframework.expression.spel.support.StandardEvaluationContext; 13 | 14 | /** 15 | * @author Created by wuhao on 2021/3/18. 16 | */ 17 | @Data 18 | public class SPELParamPredicate implements EasyRetryPredicate { 19 | 20 | private static DefaultParameterNameDiscoverer discoverer = new DefaultParameterNameDiscoverer(); 21 | 22 | private String bizIdCondition; 23 | 24 | private Method method; 25 | 26 | public SPELParamPredicate(String bizIdCondition, Method method) { 27 | this.bizIdCondition = bizIdCondition; 28 | this.method = method; 29 | } 30 | 31 | public SPELParamPredicate() { 32 | } 33 | 34 | @Override 35 | public String apply(Object[] params) { 36 | ExpressionParser parser = new SpelExpressionParser(); 37 | StandardEvaluationContext context = new StandardEvaluationContext(); 38 | String[] paramNameArr = discoverer.getParameterNames(method); 39 | if (ArrayUtils.isEmpty(paramNameArr)) { 40 | return null; 41 | } 42 | for (int i = 0; i < paramNameArr.length; i++) { 43 | context.setVariable(paramNameArr[i], params[i]); 44 | } 45 | return parser.parseExpression(bizIdCondition).getValue(context, String.class); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /easy-retry-extensions/easy-retry-spring-extension/src/main/java/com/alibaba/easyretry/extension/spring/SPELResultPredicate.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.extension.spring; 2 | 3 | import com.alibaba.easyretry.common.AbstractResultPredicate; 4 | 5 | import lombok.Data; 6 | import org.springframework.expression.ExpressionParser; 7 | import org.springframework.expression.spel.standard.SpelExpressionParser; 8 | import org.springframework.expression.spel.support.StandardEvaluationContext; 9 | 10 | /** 11 | * @author Created by wuhao on 2021/3/18. 12 | */ 13 | @Data 14 | public class SPELResultPredicate extends AbstractResultPredicate { 15 | 16 | private String resultCondition; 17 | 18 | public SPELResultPredicate(String resultCondition) { 19 | this.resultCondition = resultCondition; 20 | } 21 | 22 | public SPELResultPredicate() { 23 | } 24 | 25 | @Override 26 | public Boolean apply(T result) { 27 | ExpressionParser parser = new SpelExpressionParser(); 28 | StandardEvaluationContext context = new StandardEvaluationContext(); 29 | context.setVariable("result", result); 30 | return parser.parseExpression(resultCondition).getValue(context, Boolean.class); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /easy-retry-extensions/easy-retry-spring-extension/src/main/java/com/alibaba/easyretry/extension/spring/SpringEventApplicationListener.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.extension.spring; 2 | 3 | import org.springframework.beans.factory.SmartInitializingSingleton; 4 | 5 | import com.alibaba.easyretry.common.filter.RetryFilterInvocationHandler; 6 | import com.alibaba.easyretry.common.filter.RetryFilterRegisterHandler; 7 | 8 | import lombok.Setter; 9 | 10 | /** 11 | * @author Created by wuhao on 2021/4/9. 12 | */ 13 | public class SpringEventApplicationListener implements SmartInitializingSingleton { 14 | 15 | @Setter 16 | private RetryFilterInvocationHandler retryFilterInvocationHandler; 17 | 18 | @Setter 19 | private RetryFilterRegisterHandler retryFilterRegisterHandler; 20 | 21 | 22 | @Override 23 | public void afterSingletonsInstantiated() { 24 | retryFilterRegisterHandler.handle(); 25 | retryFilterInvocationHandler.handle(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /easy-retry-extensions/easy-retry-spring-extension/src/main/java/com/alibaba/easyretry/extension/spring/SpringRetryFilterDiscover.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.extension.spring; 2 | 3 | import java.util.List; 4 | import java.util.Map; 5 | 6 | import com.alibaba.easyretry.common.filter.RetryFilter; 7 | import com.alibaba.easyretry.common.filter.RetryFilterDiscover; 8 | 9 | import com.google.common.collect.Lists; 10 | import org.springframework.beans.BeansException; 11 | import org.springframework.beans.factory.SmartInitializingSingleton; 12 | import org.springframework.context.ApplicationContext; 13 | import org.springframework.context.ApplicationContextAware; 14 | 15 | /** 16 | * @author Created by wuhao on 2021/4/9. 17 | */ 18 | public class SpringRetryFilterDiscover implements RetryFilterDiscover, SmartInitializingSingleton, 19 | ApplicationContextAware { 20 | 21 | private List retryFilters; 22 | 23 | private ApplicationContext applicationContext; 24 | 25 | @Override 26 | public List discoverAll() { 27 | return retryFilters; 28 | } 29 | 30 | @Override 31 | public void afterSingletonsInstantiated() { 32 | Map retryFilterMap = applicationContext.getBeansOfType(RetryFilter.class); 33 | retryFilters = Lists.newArrayList(retryFilterMap.values()); 34 | } 35 | 36 | @Override 37 | public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { 38 | this.applicationContext = applicationContext; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /easy-retry-extensions/easy-retry-spring-extension/src/main/java/com/alibaba/easyretry/extension/spring/aop/EasyRetryable.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.extension.spring.aop; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | import com.alibaba.easyretry.common.constant.enums.RetryTypeEnum; 9 | 10 | @Target({ElementType.METHOD}) 11 | @Retention(RetentionPolicy.RUNTIME) 12 | public @interface EasyRetryable { 13 | 14 | /** 15 | * 处理完成以后是否需要把异常重新抛出 16 | * 17 | * @return 是否需要抛出异 18 | */ 19 | boolean reThrowException() default false; 20 | 21 | /** 22 | * 通过结果判断是否重试 23 | */ 24 | String resultCondition() default ""; 25 | 26 | /** 27 | * 重试种类 28 | */ 29 | RetryTypeEnum retryType() default RetryTypeEnum.ASYNC; 30 | 31 | } 32 | -------------------------------------------------------------------------------- /easy-retry-extensions/easy-retry-spring-extension/src/main/java/com/alibaba/easyretry/extension/spring/aop/RetryInterceptor.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.extension.spring.aop; 2 | 3 | import java.lang.reflect.Method; 4 | import java.util.Objects; 5 | 6 | import com.alibaba.easyretry.common.RetryConfiguration; 7 | import com.alibaba.easyretry.common.RetryIdentify; 8 | import com.alibaba.easyretry.common.retryer.Retryer; 9 | import com.alibaba.easyretry.core.RetryerBuilder; 10 | import com.alibaba.easyretry.extension.spring.SPELResultPredicate; 11 | 12 | import lombok.Setter; 13 | import org.apache.commons.lang3.StringUtils; 14 | import org.aspectj.lang.ProceedingJoinPoint; 15 | import org.aspectj.lang.annotation.Around; 16 | import org.aspectj.lang.annotation.Aspect; 17 | import org.aspectj.lang.reflect.MethodSignature; 18 | import org.springframework.context.ApplicationContext; 19 | 20 | @Aspect 21 | public class RetryInterceptor { 22 | 23 | @Setter 24 | private RetryConfiguration retryConfiguration; 25 | 26 | @Setter 27 | private ApplicationContext applicationContext; 28 | 29 | @Around("@annotation(retryable)") 30 | public Object around(ProceedingJoinPoint invocation, EasyRetryable retryable) throws Throwable { 31 | if (RetryIdentify.isOnRetry()) { 32 | return invocation.proceed(); 33 | } 34 | 35 | Retryer retryer = determineTargetRetryer(invocation, retryable); 36 | return retryer.call(invocation::proceed); 37 | } 38 | 39 | private String getBeanId(Class type) { 40 | String[] names = applicationContext.getBeanNamesForType(type); 41 | return names.length > 0 ? names[0] : null; 42 | } 43 | 44 | private Retryer determineTargetRetryer(ProceedingJoinPoint invocation, EasyRetryable retryable) { 45 | MethodSignature signature = (MethodSignature)invocation.getSignature(); 46 | RetryerBuilder retryerBuilder = new RetryerBuilder() 47 | .withExecutorName(getBeanId(signature.getDeclaringType())) 48 | .withExecutorMethodName(signature.getMethod().getName()) 49 | .withArgs(invocation.getArgs()) 50 | .withConfiguration(retryConfiguration) 51 | .withReThrowException(retryable.reThrowException()); 52 | if (StringUtils.isNotBlank(retryable.resultCondition())) { 53 | retryerBuilder.withResultPredicate(new SPELResultPredicate<>(retryable.resultCondition())); 54 | } 55 | 56 | return retryerBuilder.build(retryable.retryType()); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /easy-retry-extensions/pom.xml: -------------------------------------------------------------------------------- 1 | 4 | 4.0.0 5 | 6 | com.alibaba 7 | easy-retry 8 | ${revision} 9 | ../pom.xml 10 | 11 | 12 | easy-retry-extensions 13 | pom 14 | 15 | easy-retry-extensions 16 | easy-retry-extensions 17 | 18 | 19 | easy-retry-spring-extension 20 | easy-retry-mybatis-extension 21 | easy-retry-guava-extension 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /easy-retry-starters/easy-retry-memory-starter/pom.xml: -------------------------------------------------------------------------------- 1 | 4 | 4.0.0 5 | 6 | com.alibaba 7 | easy-retry-starters 8 | ${revision} 9 | ../pom.xml 10 | 11 | 12 | easy-retry-memory-starter 13 | easy-retry-memory-starter 14 | easy-retry-memory-starter 15 | 16 | 17 | org.springframework.boot 18 | spring-boot-autoconfigure 19 | 20 | 21 | 22 | ${project.groupId} 23 | easy-retry-spring-extension 24 | 25 | 26 | 27 | ${project.groupId} 28 | easy-retry-core 29 | 30 | 31 | ${project.groupId} 32 | easy-retry-starter-common 33 | 34 | 35 | -------------------------------------------------------------------------------- /easy-retry-starters/easy-retry-memory-starter/src/main/java/com/alibaba/easyretry/memory/MemoryAutoConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.memory; 2 | 3 | import com.alibaba.easyretry.common.RetryConfiguration; 4 | import com.alibaba.easyretry.common.RetryContainer; 5 | import com.alibaba.easyretry.common.RetryExecutor; 6 | import com.alibaba.easyretry.core.access.MemoryRetryTaskAccess; 7 | import com.alibaba.easyretry.core.container.SimpleRetryContainer; 8 | import com.alibaba.easyretry.memory.config.EasyRetryMemoryCompatibleProperties; 9 | import com.alibaba.easyretry.starter.common.CommonAutoConfiguration; 10 | import lombok.extern.slf4j.Slf4j; 11 | import org.springframework.beans.BeansException; 12 | import org.springframework.beans.factory.annotation.Autowired; 13 | import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; 14 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; 15 | import org.springframework.boot.context.properties.EnableConfigurationProperties; 16 | import org.springframework.context.ApplicationContext; 17 | import org.springframework.context.annotation.Bean; 18 | import org.springframework.context.annotation.Configuration; 19 | 20 | /** 21 | * @author Created by wuhao on 2021/2/19. 22 | */ 23 | @Configuration 24 | @Slf4j 25 | @EnableConfigurationProperties(EasyRetryMemoryCompatibleProperties.class) 26 | @ConditionalOnProperty(name = "spring.easyretry.memory.enabled", havingValue = "true") 27 | public class MemoryAutoConfiguration extends CommonAutoConfiguration { 28 | 29 | @Autowired 30 | private EasyRetryMemoryCompatibleProperties easyRetryMemoryCompatibleProperties; 31 | 32 | @Bean 33 | @ConditionalOnMissingBean(MemoryRetryTaskAccess.class) 34 | public MemoryRetryTaskAccess retryTaskAccess() { 35 | return new MemoryRetryTaskAccess(); 36 | } 37 | 38 | @Bean(initMethod = "start") 39 | public RetryContainer retryContainer( 40 | RetryConfiguration configuration, RetryExecutor defaultRetryExecutor) { 41 | log.warn("RetryConfiguration start"); 42 | return new SimpleRetryContainer( 43 | configuration, 44 | defaultRetryExecutor); 45 | } 46 | 47 | @Override 48 | public Integer getMaxRetryTimes() { 49 | return easyRetryMemoryCompatibleProperties.getMaxRetryTimes(); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /easy-retry-starters/easy-retry-memory-starter/src/main/java/com/alibaba/easyretry/memory/config/EasyRetryMemoryCompatibleProperties.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.memory.config; 2 | 3 | import lombok.Data; 4 | import org.springframework.boot.context.properties.ConfigurationProperties; 5 | 6 | /** 7 | * @author Created by wuhao on 2021/2/21. 8 | */ 9 | @ConfigurationProperties(prefix = "spring.easyretry.memory") 10 | @Data 11 | public class EasyRetryMemoryCompatibleProperties { 12 | 13 | private Integer maxRetryTimes = 5; 14 | 15 | private String namespace = "easy-retry"; 16 | } 17 | -------------------------------------------------------------------------------- /easy-retry-starters/easy-retry-memory-starter/src/main/resources/META-INF/additional-spring-configuration-metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "properties": [ 3 | { 4 | "name": "spring.easyretry.memory.enabled", 5 | "type": "java.lang.Boolean", 6 | "description": "enable AmoebaCompatible or not." 7 | }, 8 | { 9 | "name": "spring.easyretry.memory.maxRetryTimes", 10 | "type": "java.lang.Integer", 11 | "description": "definition the maxRetryTimes" 12 | } 13 | ] 14 | } -------------------------------------------------------------------------------- /easy-retry-starters/easy-retry-memory-starter/src/main/resources/META-INF/spring.factories: -------------------------------------------------------------------------------- 1 | org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ 2 | com.alibaba.easyretry.memory.MemoryAutoConfiguration -------------------------------------------------------------------------------- /easy-retry-starters/easy-retry-mybatis-starter/pom.xml: -------------------------------------------------------------------------------- 1 | 4 | 4.0.0 5 | 6 | com.alibaba 7 | easy-retry-starters 8 | ${revision} 9 | ../pom.xml 10 | 11 | 12 | easy-retry-mybatis-starter 13 | easy-retry-mybatis-starter 14 | easy-retry-mybatis-starter 15 | 16 | 17 | org.springframework.boot 18 | spring-boot-autoconfigure 19 | 20 | 21 | 22 | com.alibaba 23 | easy-retry-spring-extension 24 | 25 | 26 | 27 | ${project.groupId} 28 | easy-retry-core 29 | 30 | 31 | 32 | ${project.groupId} 33 | easy-retry-mybatis-extension 34 | 35 | 36 | 37 | org.mybatis 38 | mybatis-spring 39 | 2.0.6 40 | 41 | 42 | 43 | org.springframework 44 | spring-tx 45 | 5.1.12.RELEASE 46 | 47 | 48 | 49 | ${project.groupId} 50 | easy-retry-starter-common 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /easy-retry-starters/easy-retry-mybatis-starter/src/main/java/com/alibaba/easyretry/mybatis/MybatisAutoConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.mybatis; 2 | 3 | import com.alibaba.easyretry.common.RetryConfiguration; 4 | import com.alibaba.easyretry.common.RetryContainer; 5 | import com.alibaba.easyretry.common.RetryExecutor; 6 | import com.alibaba.easyretry.common.access.RetryTaskAccess; 7 | import com.alibaba.easyretry.core.container.SimpleRetryContainer; 8 | import com.alibaba.easyretry.extension.mybatis.access.MybatisRetryTaskAccess; 9 | import com.alibaba.easyretry.extension.mybatis.dao.RetryTaskDAO; 10 | import com.alibaba.easyretry.extension.mybatis.dao.RetryTaskDAOImpl; 11 | import com.alibaba.easyretry.mybatis.conifg.EasyRetryMybatisProperties; 12 | import com.alibaba.easyretry.starter.common.CommonAutoConfiguration; 13 | import lombok.extern.slf4j.Slf4j; 14 | import org.apache.ibatis.session.SqlSessionFactory; 15 | import org.mybatis.spring.SqlSessionFactoryBean; 16 | import org.springframework.beans.BeansException; 17 | import org.springframework.beans.factory.annotation.Autowired; 18 | import org.springframework.beans.factory.annotation.Qualifier; 19 | import org.springframework.beans.factory.annotation.Value; 20 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; 21 | import org.springframework.boot.context.properties.EnableConfigurationProperties; 22 | import org.springframework.context.ApplicationContext; 23 | import org.springframework.context.annotation.Bean; 24 | import org.springframework.context.annotation.Configuration; 25 | import org.springframework.core.io.Resource; 26 | 27 | import javax.sql.DataSource; 28 | 29 | /** 30 | * @author Created by wuhao on 2021/2/19. 31 | */ 32 | @Configuration 33 | @Slf4j 34 | @EnableConfigurationProperties(EasyRetryMybatisProperties.class) 35 | @ConditionalOnProperty(name = "spring.easyretry.mybatis.enabled", matchIfMissing = true) 36 | public class MybatisAutoConfiguration extends CommonAutoConfiguration { 37 | 38 | @Autowired 39 | private EasyRetryMybatisProperties easyRetryMybatisProperties; 40 | 41 | @Value("classpath:/dal/easyretry/easy-mybatis-config.xml") 42 | private Resource easyRetryMybatisResouse; 43 | 44 | @Bean("easyRetrySqlSessionFactory") 45 | public SqlSessionFactory sqlSessionFactory( 46 | @Qualifier("easyRetryMybatisDataSource") DataSource easyRetryMybatisDataSource) 47 | throws Exception { 48 | SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean(); 49 | sqlSessionFactoryBean.setDataSource(easyRetryMybatisDataSource); 50 | sqlSessionFactoryBean.setConfigLocation(easyRetryMybatisResouse); 51 | return sqlSessionFactoryBean.getObject(); 52 | } 53 | 54 | @Bean(initMethod = "start") 55 | public RetryContainer retryContainer( 56 | RetryConfiguration configuration, RetryExecutor defaultRetryExecutor) { 57 | log.warn("RetryConfiguration start"); 58 | return new SimpleRetryContainer( 59 | configuration, defaultRetryExecutor); 60 | } 61 | 62 | @Bean 63 | public RetryTaskDAO retryTaskDAO( 64 | @Qualifier("easyRetrySqlSessionFactory") SqlSessionFactory sqlSessionFactory) { 65 | return new RetryTaskDAOImpl(sqlSessionFactory); 66 | } 67 | 68 | @Bean 69 | public RetryTaskAccess retryTaskAccess(RetryTaskDAO retryTaskDAO) { 70 | return new MybatisRetryTaskAccess(retryTaskDAO); 71 | } 72 | 73 | @Override 74 | public Integer getMaxRetryTimes() { 75 | return easyRetryMybatisProperties.getMaxRetryTimes(); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /easy-retry-starters/easy-retry-mybatis-starter/src/main/java/com/alibaba/easyretry/mybatis/conifg/EasyRetryMybatisProperties.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.mybatis.conifg; 2 | 3 | import lombok.Data; 4 | import org.springframework.boot.context.properties.ConfigurationProperties; 5 | 6 | /** 7 | * @author Created by wuhao on 2021/2/21. 8 | */ 9 | @ConfigurationProperties(prefix = "spring.easyretry.mybatis") 10 | @Data 11 | public class EasyRetryMybatisProperties { 12 | 13 | private Integer maxRetryTimes = 5; 14 | 15 | } 16 | -------------------------------------------------------------------------------- /easy-retry-starters/easy-retry-mybatis-starter/src/main/resources/META-INF/additional-spring-configuration-metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "properties": [ 3 | { 4 | "name": "spring.easyretry.mybatis.enabled", 5 | "type": "java.lang.Boolean", 6 | "description": "enable AmoebaCompatible or not." 7 | }, 8 | { 9 | "name": "spring.easyretry.mybatis.maxRetryTimes", 10 | "type": "java.lang.Integer", 11 | "description": "definition the maxRetryTimes" 12 | } 13 | ] 14 | } -------------------------------------------------------------------------------- /easy-retry-starters/easy-retry-mybatis-starter/src/main/resources/META-INF/spring.factories: -------------------------------------------------------------------------------- 1 | org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ 2 | com.alibaba.easyretry.mybatis.MybatisAutoConfiguration -------------------------------------------------------------------------------- /easy-retry-starters/easy-retry-starter-common/pom.xml: -------------------------------------------------------------------------------- 1 | 4 | 4.0.0 5 | 6 | com.alibaba 7 | easy-retry-starters 8 | ${revision} 9 | ../pom.xml 10 | 11 | 12 | easy-retry-starter-common 13 | easy-retry-starter-common 14 | easy-retry-starter-common 15 | 16 | 17 | org.springframework.boot 18 | spring-boot-autoconfigure 19 | 20 | 21 | 22 | com.alibaba 23 | easy-retry-spring-extension 24 | 25 | 26 | 27 | com.alibaba 28 | easy-retry-guava-extension 29 | 30 | 31 | 32 | ${project.groupId} 33 | easy-retry-core 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /easy-retry-starters/easy-retry-starter-common/src/main/java/com/alibaba/easyretry/starter/common/CommonAutoConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.alibaba.easyretry.starter.common; 2 | 3 | import org.springframework.beans.BeansException; 4 | import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; 5 | import org.springframework.context.ApplicationContext; 6 | import org.springframework.context.ApplicationContextAware; 7 | import org.springframework.context.annotation.Bean; 8 | 9 | import com.alibaba.easyretry.common.RetryConfiguration; 10 | import com.alibaba.easyretry.common.RetryExecutor; 11 | import com.alibaba.easyretry.common.access.RetrySerializerAccess; 12 | import com.alibaba.easyretry.common.access.RetryStrategyAccess; 13 | import com.alibaba.easyretry.common.access.RetryTaskAccess; 14 | import com.alibaba.easyretry.common.event.RetryEventMulticaster; 15 | import com.alibaba.easyretry.common.filter.RetryFilterDiscover; 16 | import com.alibaba.easyretry.common.filter.RetryFilterInvocation; 17 | import com.alibaba.easyretry.common.filter.RetryFilterInvocationHandler; 18 | import com.alibaba.easyretry.common.filter.RetryFilterRegister; 19 | import com.alibaba.easyretry.common.filter.RetryFilterRegisterHandler; 20 | import com.alibaba.easyretry.common.resolve.ExecutorSolver; 21 | import com.alibaba.easyretry.common.serializer.ResultPredicateSerializer; 22 | import com.alibaba.easyretry.common.strategy.StopStrategy; 23 | import com.alibaba.easyretry.common.strategy.WaitStrategy; 24 | import com.alibaba.easyretry.core.PersistenceRetryExecutor; 25 | import com.alibaba.easyretry.core.access.DefaultRetrySerializerAccess; 26 | import com.alibaba.easyretry.core.event.SimpleRetryEventMulticaster; 27 | import com.alibaba.easyretry.core.filter.DefaultRetryFilterInvocationHandler; 28 | import com.alibaba.easyretry.core.filter.DefaultRetryFilterRegisterHandler; 29 | import com.alibaba.easyretry.core.filter.SimpleRetryFilterRegister; 30 | import com.alibaba.easyretry.core.serializer.HessianResultPredicateSerializer; 31 | import com.alibaba.easyretry.core.strategy.DefaultRetryStrategy; 32 | import com.alibaba.easyretry.extension.spring.RetryListenerInitialize; 33 | import com.alibaba.easyretry.extension.spring.SpringEventApplicationListener; 34 | import com.alibaba.easyretry.extension.spring.SpringRetryFilterDiscover; 35 | import com.alibaba.easyretry.extension.spring.aop.RetryInterceptor; 36 | 37 | import lombok.extern.slf4j.Slf4j; 38 | 39 | /** 40 | * @author Created by wuhao on 2021/2/19. 41 | */ 42 | @Slf4j 43 | public abstract class CommonAutoConfiguration implements ApplicationContextAware { 44 | 45 | protected ApplicationContext applicationContext; 46 | 47 | @Bean 48 | @ConditionalOnMissingBean(RetryConfiguration.class) 49 | public RetryConfiguration configuration(RetryTaskAccess retryTaskAccess, 50 | RetryEventMulticaster retryEventMulticaster) { 51 | DefaultRetryStrategy defaultRetryStrategy = new DefaultRetryStrategy(); 52 | return new RetryConfiguration() { 53 | @Override 54 | public RetryTaskAccess getRetryTaskAccess() { 55 | return retryTaskAccess; 56 | } 57 | 58 | @Override 59 | public RetrySerializerAccess getRetrySerializerAccess() { 60 | return new DefaultRetrySerializerAccess(); 61 | } 62 | 63 | @Override 64 | public RetryStrategyAccess getRetryStrategyAccess() { 65 | return new RetryStrategyAccess() { 66 | 67 | @Override 68 | public StopStrategy getCurrentGlobalStopStrategy() { 69 | return defaultRetryStrategy; 70 | } 71 | 72 | @Override 73 | public WaitStrategy getCurrentGlobalWaitStrategy() { 74 | return defaultRetryStrategy; 75 | } 76 | }; 77 | } 78 | 79 | @Override 80 | public ExecutorSolver getExecutorSolver() { 81 | return executorName -> applicationContext.getBean(executorName); 82 | } 83 | 84 | @Override 85 | public ResultPredicateSerializer getResultPredicateSerializer() { 86 | return new HessianResultPredicateSerializer(); 87 | } 88 | 89 | @Override 90 | public Integer getMaxRetryTimes() { 91 | return CommonAutoConfiguration.this.getMaxRetryTimes(); 92 | } 93 | 94 | @Override 95 | public RetryEventMulticaster getRetryEventMulticaster() { 96 | return retryEventMulticaster; 97 | } 98 | }; 99 | } 100 | 101 | @Bean 102 | @ConditionalOnMissingBean(RetryInterceptor.class) 103 | public RetryInterceptor retryInterceptor(RetryConfiguration configuration) { 104 | RetryInterceptor retryInterceptor = new RetryInterceptor(); 105 | retryInterceptor.setApplicationContext(applicationContext); 106 | retryInterceptor.setRetryConfiguration(configuration); 107 | return retryInterceptor; 108 | } 109 | 110 | @Bean 111 | @ConditionalOnMissingBean(RetryExecutor.class) 112 | public RetryExecutor defaultRetryExecutor(RetryConfiguration configuration, 113 | RetryFilterInvocation retryInvocationHandler) { 114 | PersistenceRetryExecutor persistenceRetryExecutor = new PersistenceRetryExecutor(); 115 | persistenceRetryExecutor.setRetryConfiguration(configuration); 116 | persistenceRetryExecutor.setRetryFilterInvocation(retryInvocationHandler); 117 | return persistenceRetryExecutor; 118 | } 119 | 120 | @Bean 121 | @ConditionalOnMissingBean(RetryEventMulticaster.class) 122 | public RetryEventMulticaster retryEventMulticaster() { 123 | return new SimpleRetryEventMulticaster(); 124 | } 125 | 126 | @Bean 127 | @ConditionalOnMissingBean(RetryListenerInitialize.class) 128 | public RetryListenerInitialize retryListenerInitialize(RetryEventMulticaster retryEventMulticaster) { 129 | RetryListenerInitialize retryListenerInitialize = new RetryListenerInitialize(); 130 | retryListenerInitialize.setRetryEventMulticaster(retryEventMulticaster); 131 | return retryListenerInitialize; 132 | } 133 | 134 | @Bean 135 | @ConditionalOnMissingBean(SpringRetryFilterDiscover.class) 136 | public SpringRetryFilterDiscover springRetryFilterDiscover() { 137 | return new SpringRetryFilterDiscover(); 138 | } 139 | 140 | @Bean 141 | @ConditionalOnMissingBean(RetryFilterRegister.class) 142 | public SimpleRetryFilterRegister simpleRetryFilterRegister() { 143 | return new SimpleRetryFilterRegister(); 144 | } 145 | 146 | @Bean 147 | @ConditionalOnMissingBean(RetryFilterInvocationHandler.class) 148 | public DefaultRetryFilterInvocationHandler retryInvocationHandler(RetryFilterRegister simpleRetryFilterRegister) { 149 | DefaultRetryFilterInvocationHandler defaultRetryFilterInvocationHandler 150 | = new DefaultRetryFilterInvocationHandler(); 151 | defaultRetryFilterInvocationHandler.setRetryFilterRegister(simpleRetryFilterRegister); 152 | return defaultRetryFilterInvocationHandler; 153 | } 154 | 155 | @Bean 156 | @ConditionalOnMissingBean(RetryFilterRegisterHandler.class) 157 | public RetryFilterRegisterHandler retryFilterRegisterHandler(RetryFilterDiscover springRetryFilterDiscover, 158 | RetryFilterRegister simpleRetryFilterRegister) { 159 | DefaultRetryFilterRegisterHandler defaultRetryFilterRegisterHandler = new DefaultRetryFilterRegisterHandler(); 160 | defaultRetryFilterRegisterHandler.setRetryFilterRegister(simpleRetryFilterRegister); 161 | defaultRetryFilterRegisterHandler.setRetryFilterDiscover(springRetryFilterDiscover); 162 | return defaultRetryFilterRegisterHandler; 163 | } 164 | 165 | @Bean 166 | public SpringEventApplicationListener easyRetryApplicationListener(RetryFilterInvocationHandler retryFilterInvocationHandler, 167 | RetryFilterRegisterHandler retryFilterRegisterHandler) { 168 | SpringEventApplicationListener springEventApplicationListener = new SpringEventApplicationListener(); 169 | springEventApplicationListener.setRetryFilterRegisterHandler(retryFilterRegisterHandler); 170 | springEventApplicationListener.setRetryFilterInvocationHandler(retryFilterInvocationHandler); 171 | return springEventApplicationListener; 172 | } 173 | 174 | @Override 175 | public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { 176 | this.applicationContext = applicationContext; 177 | } 178 | 179 | public abstract Integer getMaxRetryTimes(); 180 | 181 | } 182 | -------------------------------------------------------------------------------- /easy-retry-starters/pom.xml: -------------------------------------------------------------------------------- 1 | 4 | 4.0.0 5 | 6 | com.alibaba 7 | easy-retry 8 | ${revision} 9 | ../pom.xml 10 | 11 | 12 | easy-retry-starters 13 | pom 14 | 15 | easy-retry-starters 16 | easy-retry-starters 17 | 18 | 19 | easy-retry-memory-starter 20 | easy-retry-mybatis-starter 21 | easy-retry-starter-common 22 | 23 | 24 | 25 | 26 | 27 | org.springframework.boot 28 | spring-boot-autoconfigure 29 | 2.4.0 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /img/readme/arch.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alibaba/easy-retry/86b831c436bcf95bc5c6e671f2c3ea2fa1c3f613/img/readme/arch.jpg -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 4.0.0 7 | com.alibaba 8 | easy-retry 9 | ${revision} 10 | pom 11 | 12 | 1.8 13 | 1.8 14 | 1.8 15 | UTF-8 16 | UTF-8 17 | 1.0.3 18 | 1.7.30 19 | 1.18.18 20 | 16.0 21 | 1.2.73 22 | 2.2.1 23 | 3.2.0 24 | 1.6 25 | 26 | 27 | easy-retry-common 28 | easy-retry-core 29 | easy-retry-extensions 30 | easy-retry-starters 31 | 32 | 33 | easy-retry 34 | easy-retry 35 | https://github.com/alibaba/easy-retry 36 | 37 | 38 | 39 | https://github.com/alibaba/easy-retry 40 | scm:git@github.com:alibaba/easy-retry.git 41 | 42 | 43 | 44 | Alibaba Group 45 | https://github.com/alibaba 46 | 47 | 48 | 49 | 50 | wuhao 51 | wuhao7171@gmail.com 52 | 53 | 54 | 55 | 56 | 57 | MIT License 58 | http://www.opensource.org/licenses/mit-license.php 59 | 60 | 61 | 62 | 63 | 64 | org.junit.jupiter 65 | junit-jupiter 66 | test 67 | 68 | 69 | 70 | 71 | 72 | 73 | org.junit 74 | junit-bom 75 | 5.7.1 76 | pom 77 | import 78 | 79 | 80 | 81 | org.slf4j 82 | slf4j-api 83 | ${slf4j.version} 84 | 85 | 86 | org.projectlombok 87 | lombok 88 | ${lombok.version} 89 | true 90 | 91 | 92 | 93 | com.google.guava 94 | guava 95 | ${guava.version} 96 | 97 | 98 | 99 | com.alibaba 100 | easy-retry-core 101 | ${project.version} 102 | 103 | 104 | 105 | com.alibaba 106 | easy-retry-common 107 | ${project.version} 108 | 109 | 110 | 111 | com.caucho 112 | hessian 113 | 4.0.60 114 | provided 115 | 116 | 117 | 118 | org.apache.commons 119 | commons-lang3 120 | 3.11 121 | 122 | 123 | 124 | com.alibaba 125 | fastjson 126 | ${fastjson.version} 127 | 128 | 129 | 130 | org.apache.commons 131 | commons-collections4 132 | 4.4 133 | 134 | 135 | ${project.groupId} 136 | easy-retry-spring-extension 137 | ${project.version} 138 | 139 | 140 | ${project.groupId} 141 | easy-retry-guava-extension 142 | ${project.version} 143 | 144 | 145 | 146 | ${project.groupId} 147 | easy-retry-mybatis-extension 148 | ${project.version} 149 | 150 | 151 | 152 | ${project.groupId} 153 | easy-retry-starter-common 154 | ${project.version} 155 | 156 | 157 | 158 | 159 | 160 | 161 | org.apache.maven.plugins 162 | maven-compiler-plugin 163 | 3.8.1 164 | 165 | 1.8 166 | 1.8 167 | UTF-8 168 | 169 | 170 | 171 | 172 | org.apache.maven.plugins 173 | maven-resources-plugin 174 | 3.2.0 175 | 176 | UTF-8 177 | 178 | 179 | 180 | 181 | org.codehaus.mojo 182 | flatten-maven-plugin 183 | 1.1.0 184 | 185 | true 186 | oss 187 | 188 | 189 | 190 | flatten 191 | process-resources 192 | 193 | flatten 194 | 195 | 196 | 197 | flatten.clean 198 | clean 199 | 200 | clean 201 | 202 | 203 | 204 | 205 | 206 | 207 | org.apache.maven.plugins 208 | maven-surefire-plugin 209 | 3.0.0-M5 210 | 211 | 212 | 213 | 214 | 215 | 216 | release 217 | 218 | 219 | 220 | org.apache.maven.plugins 221 | maven-gpg-plugin 222 | ${maven-gpg-plugin.version} 223 | 224 | 225 | verify 226 | 227 | sign 228 | 229 | 230 | 231 | 232 | 233 | 234 | org.apache.maven.plugins 235 | maven-source-plugin 236 | 3.2.1 237 | 238 | 239 | attach-sources 240 | 241 | jar 242 | 243 | 244 | 245 | 246 | 247 | 248 | org.apache.maven.plugins 249 | maven-javadoc-plugin 250 | ${maven-javadoc-plugin.version} 251 | 252 | 253 | attach-javadocs 254 | 255 | jar 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | esnapshots 266 | https://oss.sonatype.org/content/repositories/snapshots 267 | 268 | 269 | erelease 270 | https://oss.sonatype.org/service/local/staging/deploy/maven2/ 271 | 272 | 273 | 274 | 275 | 276 | --------------------------------------------------------------------------------