commit 47c9fb863dbd3c811294a5abf03975ae947d4867 Author: byteblogs168 <598092184@qq.com> Date: Sat Sep 2 17:24:47 2023 +0800 easy retry demo 初始化 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8f237d5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,31 @@ +HELP.md +/target/ +!.mvn/wrapper/maven-wrapper.jar + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +/build/ + +### VS Code ### +.vscode/ + +.flattened-pom.xml diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..36a80aa --- /dev/null +++ b/Dockerfile @@ -0,0 +1,13 @@ +FROM openjdk:8-jdk-alpine +MAINTAINER www.byteblogs.com + +ADD ./target/easy-retry-example.jar easy-retry-example.jar + +#对外暴漏的端口号 +EXPOSE 8018 + +WORKDIR / + +#开机启动 +ENTRYPOINT ["sh","-c","java -jar $JAVA_OPTS /easy-retry-example.jar $PARAMS"] + diff --git a/docs/demo.sql b/docs/demo.sql new file mode 100644 index 0000000..7aef6ef --- /dev/null +++ b/docs/demo.sql @@ -0,0 +1,15 @@ +DROP DATABASE IF EXISTS demo; +CREATE DATABASE demo; +USE demo; + +CREATE TABLE `demo`.`fail_order` ( + `id` bigint NOT NULL COMMENT '自增主键Id', + `orderId` bigint NOT NULL COMMENT '订单Id', + `sourceId` int NOT NULL COMMENT '来源Id', + `sceneName` varchar(255) NOT NULL COMMENT '场景名称', + `executorName` varchar(255) NOT NULL COMMENT '执行器名称', + `args` varchar(255) NULL COMMENT '参数信息', + `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`id`) + ); \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..b854008 --- /dev/null +++ b/pom.xml @@ -0,0 +1,111 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.6.8 + + + + com.example + example + 1.0.0 + example + Demo project for Spring Boot + + + 1.8 + + + + + org.springframework.boot + spring-boot-starter-web + + + + org.projectlombok + lombok + true + + + org.springframework.boot + spring-boot-starter-test + test + + + com.aizuda + easy-retry-client-starter + 2.2.0 + + + com.baomidou + mybatis-plus-boot-starter + 3.5.1 + + + com.baomidou + mybatis-plus-generator + 3.5.1 + + + org.freemarker + freemarker + 2.3.28 + compile + + + cn.hutool + hutool-all + 5.8.19 + + + mysql + mysql-connector-java + 8.0.30 + + + + io.springfox + springfox-boot-starter + 3.0.0 + + + + com.alibaba + transmittable-thread-local + 2.12.0 + + + org.awaitility + awaitility + 4.1.1 + + + com.squareup.okhttp3 + okhttp + 4.2.0 + + + + + easy-retry-example + + + org.springframework.boot + spring-boot-maven-plugin + + + + org.projectlombok + lombok + + + + + + + + diff --git a/src/main/java/com/example/easy/retry/EasyRetrySpringbootApplication.java b/src/main/java/com/example/easy/retry/EasyRetrySpringbootApplication.java new file mode 100644 index 0000000..f062672 --- /dev/null +++ b/src/main/java/com/example/easy/retry/EasyRetrySpringbootApplication.java @@ -0,0 +1,17 @@ +package com.example.easy.retry; + +import com.aizuda.easy.retry.client.starter.EnableEasyRetry; +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +@EnableEasyRetry(group = "easy_retry_demo_group") +@MapperScan("com.example.easy.retry.dao") +public class EasyRetrySpringbootApplication { + + public static void main(String[] args) { + SpringApplication.run(EasyRetrySpringbootApplication.class, args); + } + +} diff --git a/src/main/java/com/example/easy/retry/config/SwaggerConfig.java b/src/main/java/com/example/easy/retry/config/SwaggerConfig.java new file mode 100644 index 0000000..128c8c2 --- /dev/null +++ b/src/main/java/com/example/easy/retry/config/SwaggerConfig.java @@ -0,0 +1,51 @@ +package com.example.easy.retry.config; + +import com.aizuda.easy.retry.common.core.util.EasyRetryVersion; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import springfox.documentation.builders.ApiInfoBuilder; +import springfox.documentation.builders.PathSelectors; +import springfox.documentation.builders.RequestHandlerSelectors; +import springfox.documentation.service.ApiInfo; +import springfox.documentation.spi.DocumentationType; +import springfox.documentation.spring.web.plugins.Docket; +import springfox.documentation.swagger2.annotations.EnableSwagger2; + +/** + * @author: www.byteblogs.com + * @date : 2023-07-17 18:19 + * @since 2.1.0 + */ +@Configuration +@EnableSwagger2 +public class SwaggerConfig { + @Bean + public Docket api() { + return new Docket(DocumentationType.SWAGGER_2) + .select() + .apis(RequestHandlerSelectors.basePackage("com.example.easy.retry.controller")) // 替换为你的项目包名 + .paths(PathSelectors.any()) + .build() + .apiInfo(apiInfo()); + } + + private ApiInfo apiInfo() { + return new ApiInfoBuilder() + .title("Easy Retry Example") + .description( + "

EasyRetry是基于BASE思想实现的分布式服务重试组件

\n" + + "

官网地址: https://www.easyretry.com/

" + + "

在线体验地址: http://preview.easyretry.com/

"+ + "

源码地址: https://gitee.com/byteblogs168/easy-retry-demo

" + + "

特别提醒: 🌻在您使用测试案例之前请认真的阅读官网.

" + ) + .version(EasyRetryVersion.getVersion()) + .build(); + } +} + + + + + + diff --git a/src/main/java/com/example/easy/retry/controller/LocalAndRemoteRetryController.java b/src/main/java/com/example/easy/retry/controller/LocalAndRemoteRetryController.java new file mode 100644 index 0000000..13e2bf9 --- /dev/null +++ b/src/main/java/com/example/easy/retry/controller/LocalAndRemoteRetryController.java @@ -0,0 +1,42 @@ +package com.example.easy.retry.controller; + +import com.example.easy.retry.service.LocalRemoteService; +import com.example.easy.retry.service.LocalRetryService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import java.util.UUID; + +@RestController +@RequestMapping("/local-remote") +@Api(value = "模拟先本地再远程重试案例", tags = "先本地再远程重试案例【RetryType.LOCAL_REMOTE】") +public class LocalAndRemoteRetryController { + + @Autowired + private LocalRemoteService localRemoteService; + + @GetMapping("/retry") + @ApiOperation(value = "一个简单的入门案例") + public void localRemote() { + localRemoteService.localRemote(); + } + + @GetMapping("/retryWithLocalRemote") + @ApiOperation( + value = "使用同步上报的方式", + notes = "async = false 代表使用同步上传的方式\n" + + "timeout = 1 代表超时时间为1 \n" + + "unit = MINUTES 代表超时时间的单位是分钟\n" + + "📢查看任务列表: http://preview.easyretry.com/#/retry-task/list" + ) + public void remoteRetryWithLocalRemote(@ApiParam(name = "params", value = "测试参数", defaultValue = "test") + @RequestParam("params") String params) { + localRemoteService.remoteRetryWithLocalRemote(params); + } +} diff --git a/src/main/java/com/example/easy/retry/controller/LocalRetryController.java b/src/main/java/com/example/easy/retry/controller/LocalRetryController.java new file mode 100644 index 0000000..2f0768d --- /dev/null +++ b/src/main/java/com/example/easy/retry/controller/LocalRetryController.java @@ -0,0 +1,86 @@ +package com.example.easy.retry.controller; + +import io.swagger.annotations.*; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import com.example.easy.retry.service.LocalRetryService; + +@RestController +@RequestMapping("/local") +@Api(value = "模拟本地重试", tags = "本地重试案例 【RetryType.ONLY_LOCAL】") +public class LocalRetryController { + + @Autowired + private LocalRetryService localRetryService; + + @GetMapping("/retry") + @ApiOperation( + value = "一个简单的入门案例", + notes = "🥇仅仅在本地进行内存重试\n" + + "📢任务列表: http://preview.easyretry.com/#/retry-task/list" + ) + public void onlyLocalRetry(@ApiParam(name = "params", value = "测试参数", defaultValue = "test") @RequestParam("params") String params){ + localRetryService.localRetry(params); + } + + @GetMapping("/withBasicParams") + @ApiOperation( + value = "指定基础参数", + notes = "localTimes 本地重试次数\n" + + "localInterval 本地重试间隔时间(默认单位为秒)\n" + + "unit 超时时间单位\n" + + "本案例设置为本地重试4次,每次重试之间间隔10s" + ) + public void localRetryWithBasicParams(@ApiParam(name = "params", value = "测试参数", defaultValue = "test") @RequestParam("params") String params){ + localRetryService.localRetryWithBasicParams(params); + } + + @GetMapping("/includeException") + @ApiOperation( + value = "指定异常参数", + notes = "include参数指的是当我们遭遇到指定异常时进行重试\n" + + "在这个案例中我们处理两个场景:\n" + + "抛出指定异常,例如抛出自定义的ParamException异常,观察是否会重试\n" + + "抛出非指定异常,例如我们在这里产生一个异常,观察是否会重试\n" + + "注意:如果此时我们在include 中指定参数为BusinessException(ParamException的父类),同样也会进行重试逻辑\n" + + "下面参数可以指定:NullPointerException, ParamException" + ) + @ApiImplicitParams({ + @ApiImplicitParam(name = "type", value = "异常类型", dataType = "String", paramType = "query", + allowableValues = "NullPointerException,ParamException", defaultValue = "ParamException") + }) + public void localRetryIncludeException(@RequestParam("type") String type){ + localRetryService.localRetryIncludeException(type); + } + + @GetMapping("/excludeException") + @ApiOperation( + value = "非指定异常参数进行重试", + notes = "这个参数的作用和include是相反的\n" + + "exclude参数指的是当我们遇到指定异常时则不会进行重试\n" + + "比如在下述案例中我们指定了遇到ParamException和ArithmeticException后不进行重试" + ) + @ApiImplicitParams({ + @ApiImplicitParam(name = "type", value = "异常类型", dataType = "String", paramType = "query", + allowableValues = "ParamException,ArithmeticException", defaultValue = "ParamException") + }) + public void localRetryExcludeException(@RequestParam("type") String type){ + localRetryService.localRetryExcludeException(type); + } + + @GetMapping("/isThrowException") + @ApiOperation( + value = "本地重试完成后不抛出异常", + notes = "" + ) + @ApiImplicitParams({ + @ApiImplicitParam(name = "params", value = "异常类型", dataType = "String", paramType = "query") + }) + public void localRetryIsThrowException(@RequestParam("params") String params){ + localRetryService.localRetryIsThrowException(params); + } +} diff --git a/src/main/java/com/example/easy/retry/controller/ManualRetryExecutorController.java b/src/main/java/com/example/easy/retry/controller/ManualRetryExecutorController.java new file mode 100644 index 0000000..73cd2d4 --- /dev/null +++ b/src/main/java/com/example/easy/retry/controller/ManualRetryExecutorController.java @@ -0,0 +1,30 @@ +package com.example.easy.retry.controller; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import com.example.easy.retry.service.ManualRetryExecutorMethodService; + +@RestController +@RequestMapping("/manual") +@Api(value = "模拟手动执行重试案例", tags = "手动执行重试上报") +public class ManualRetryExecutorController { + + @Autowired + private ManualRetryExecutorMethodService manualRetryExecutorMethodService; + @ApiOperation( + value = "手动重试", + notes = "❤️如果不知道这个手动重试的使用场景可以参考: https://www.easyretry.com/pages/406a68/#%E5%8F%91%E9%80%81mq%E5%9C%BA%E6%99%AF \n" + + "📢查看任务列表: http://preview.easyretry.com/#/retry-task/list" + ) + @GetMapping("/retry") + public void remoteRetryWithCallback(@ApiParam(name = "params", value = "测试参数", defaultValue = "test") @RequestParam("params") String params){ + manualRetryExecutorMethodService.myExecutorMethod(params); + } +} diff --git a/src/main/java/com/example/easy/retry/controller/RemoteRetryController.java b/src/main/java/com/example/easy/retry/controller/RemoteRetryController.java new file mode 100644 index 0000000..cf3cb5e --- /dev/null +++ b/src/main/java/com/example/easy/retry/controller/RemoteRetryController.java @@ -0,0 +1,165 @@ +package com.example.easy.retry.controller; + + +import java.util.Random; +import java.util.UUID; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import com.example.easy.retry.vo.OrderVo; +import com.example.easy.retry.service.RemoteRetryService; + +@RestController +@RequestMapping("/remote") +@Api(value = "模拟远程重试案例", tags = "远程重试案例【RetryType.ONLY_REMOTE】") +public class RemoteRetryController { + + @Autowired + private RemoteRetryService remoteRetryService; + + /** + * 一个最简单的远程调用案例 + */ + @GetMapping("/retry") + @ApiOperation( + value = "一个简单的入门案例", + notes = "🥇不进过本地重试阶段,直接上报到服务端\n" + + "📢查看任务列表: http://preview.easyretry.com/#/retry-task/list" + ) + public void remote(@ApiParam(name = "params", value = "测试参数", defaultValue = "test") + @RequestParam("params") String params) { + remoteRetryService.remoteRetry(params); + } + + /** + * 一个最简单的远程调用案例 + */ + @GetMapping("/retry/sync") + @ApiOperation( + value = "一个简单的以同步方式远程重试入门案例", + notes = "🥇不进过本地重试阶段,直接上报到服务端\n" + + "📢查看任务列表: http://preview.easyretry.com/#/retry-task/list" + ) + public void remoteSync(@ApiParam(name = "params", value = "测试参数", defaultValue = "test") + @RequestParam("params") String params) { + remoteRetryService.remoteSync(params); + } + + /** + * 使用自定义的幂等Id生成规则 + */ + @PostMapping("/retryWithIdempotentId") + @ApiOperation( + value = "使用自定义的幂等Id生成规则", + notes = + "具体实现类参考: https://gitee.com/zhangyutongxue/easy-retry-demo/blob/master/easy-retry-springboot/src/main/java/com/maluxinyu/easyretry/customized/OrderIdempotentIdGenerate.java\n" + + "具体的幂等策略参考: https://www.easyretry.com/pages/97cde9/#%E2%9A%A1%E5%B9%82%E7%AD%89id-idempotentid \n" + + + "📢查看任务列表: http://preview.easyretry.com/#/retry-task/list" + ) + public void remoteRetryWithIdempotentId(@RequestBody OrderVo orderVo) { + remoteRetryService.remoteRetryWithIdempotentId(orderVo); + } + + /** + * 使用自定义的单参数幂等Id生成规则 + */ + @ApiOperation( + value = "使用自定义的单参数幂等Id生成规则", + notes = + "具体实现类参考: https://gitee.com/zhangyutongxue/easy-retry-demo/blob/master/easy-retry-springboot/src/main/java/com/maluxinyu/easyretry/customized/SingleParamIdempotentGenerate.java\n" + + + "🥇通过对orderId进行md5加密生成幂等ID, 具体的幂等策略参考: https://www.easyretry.com/pages/97cde9/#%E2%9A%A1%E5%B9%82%E7%AD%89id-idempotentid \n" + + + "📢查看任务列表: http://preview.easyretry.com/#/retry-task/list" + ) + @GetMapping("/retryWithSingleParamIdempotentGenerate") + public void retryWithSingleParamIdempotentGenerate( + @ApiParam(name = "params", value = "测试参数", defaultValue = "test") + @RequestParam("params") String params) { + remoteRetryService.retryWithSingleParamIdempotentGenerate(params); + } + + /** + * 使用自定义的多参数幂等Id生成规则 + */ + @PostMapping("/retryWithMulParamIdempotentGenerate") + @ApiOperation( + value = "使用自定义的多参数幂等Id生成规则", + notes = + "具体实现类参考: https://gitee.com/zhangyutongxue/easy-retry-demo/blob/master/easy-retry-springboot/src/main/java/com/maluxinyu/easyretry/customized/MultiParamIdempotentGenerate.java\n" + + + "🥇通过对orderId进行md5加密生成幂等ID, 具体的幂等策略参考: https://www.easyretry.com/pages/97cde9/#%E2%9A%A1%E5%B9%82%E7%AD%89id-idempotentid \n" + + + "📢查看任务列表: http://preview.easyretry.com/#/retry-task/list" + ) + public void retryWithMulParamIdempotentGenerate(@RequestBody OrderVo orderVo) { + Random random = new Random(); + remoteRetryService.retryWithMulParamIdempotentGenerate( + String.valueOf(UUID.randomUUID()), + random.nextInt(), + random.nextDouble(), + 'a', + orderVo + ); + } + + /** + * 使用自定义的异常处理类 OrderRetryMethod + */ + @ApiOperation( + value = "指定自定义的异常处理类", + notes = + "具体实现类参考: https://gitee.com/zhangyutongxue/easy-retry-demo/blob/master/easy-retry-springboot/src/main/java/com/maluxinyu/easyretry/customized/OrderRetryMethod.java\n" + + + "🥇什么是自定义的异常处理类: https://www.easyretry.com/pages/540554/#%E8%87%AA%E5%AE%9A%E4%B9%89%E6%96%B9%E6%B3%95%E6%89%A7%E8%A1%8C%E5%99%A8\n" + + + "📢查看任务列表: http://preview.easyretry.com/#/retry-task/list" + ) + @PostMapping("/retryWithRetryMethod") + public void remoteRetryWithRetryMethod(@RequestBody OrderVo orderVo) { + remoteRetryService.remoteRetryWithRetryMethod(orderVo); + } + + /** + * 使用自定义的回调函数 + */ + @ApiOperation( + value = "使用自定义的回调函数", + notes = + "具体实现类参考: https://gitee.com/zhangyutongxue/easy-retry-demo/blob/master/easy-retry-springboot/src/main/java/com/maluxinyu/easyretry/customized/OrderCompleteCallback.java\n" + + + "🥇什么情况下触发回调: https://www.easyretry.com/pages/97cde9/#%E2%9A%A1%E5%9B%9E%E8%B0%83\n" + + + "📢查看任务列表: http://preview.easyretry.com/#/retry-task/list" + ) + @PostMapping("/retryWithCallback") + public void remoteRetryWithCallback(@RequestBody OrderVo orderVo) { + remoteRetryService.remoteRetryWithCompleteCallback(orderVo); + } + + /** + * 指定bizNo + */ + @ApiOperation( + value = "指定bizNo", + notes = "🥇什么是bizNo: https://www.easyretry.com/pages/540554/#bizno%E7%94%9F%E6%88%90%E5%99%A8\n" + + + "📢查看任务列表: http://preview.easyretry.com/#/retry-task/list" + ) + @PostMapping("/remoteRetryWithBizNo") + public void remoteRetryWithBizNo(@RequestBody OrderVo orderVo) { + remoteRetryService.remoteRetryWithBizNo(orderVo); + } + + +} diff --git a/src/main/java/com/example/easy/retry/customized/MultiParamIdempotentGenerate.java b/src/main/java/com/example/easy/retry/customized/MultiParamIdempotentGenerate.java new file mode 100644 index 0000000..4df8b22 --- /dev/null +++ b/src/main/java/com/example/easy/retry/customized/MultiParamIdempotentGenerate.java @@ -0,0 +1,25 @@ +package com.example.easy.retry.customized; + +import com.aizuda.easy.retry.client.core.IdempotentIdGenerate; +import com.aizuda.easy.retry.common.core.model.IdempotentIdContext; +import com.example.easy.retry.vo.OrderVo; + +import cn.hutool.crypto.SecureUtil; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class MultiParamIdempotentGenerate implements IdempotentIdGenerate { + + @Override + public String idGenerate(IdempotentIdContext idempotentIdContext) throws Exception { + Object[] args = idempotentIdContext.getArgs(); + String uuid = (String) args[0]; + Integer intVal = (Integer) args[1]; + Double doubleVal = (Double) args[2]; + Character character = (Character) args[3]; + OrderVo orderVo = (OrderVo) args[4]; + log.info("测试多参数解析,String类型:{},Integer类型:{},Double类型:{}," + + "Character类型:{},对象类型:{}",uuid,intVal,doubleVal,character,orderVo); + return SecureUtil.md5(orderVo.getOrderId()); + } +} diff --git a/src/main/java/com/example/easy/retry/customized/OrderCompleteCallback.java b/src/main/java/com/example/easy/retry/customized/OrderCompleteCallback.java new file mode 100644 index 0000000..cbf6367 --- /dev/null +++ b/src/main/java/com/example/easy/retry/customized/OrderCompleteCallback.java @@ -0,0 +1,56 @@ +package com.example.easy.retry.customized; + +import cn.hutool.json.JSONUtil; +import com.aizuda.easy.retry.client.core.callback.RetryCompleteCallback; +import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper; +import com.example.easy.retry.dao.FailOrderBaseMapper; +import com.example.easy.retry.po.FailOrderPo; +import com.example.easy.retry.vo.OrderVo; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Slf4j +@Component +public class OrderCompleteCallback implements RetryCompleteCallback { + + @Autowired + private FailOrderBaseMapper failOrderBaseMapper; + + /** + * 重试成功后的回调函数 + * 参数1-场景名称 + * 参数2-执行器名称 + * 参数3-入参信息 + */ + @Override + public void doSuccessCallback(String sceneName, String executorName, Object[] objects) { + // 重试成功后删除失败表中的数据 + OrderVo orderVo = (OrderVo) objects[0]; + log.info("远程重试成功,场景{},执行器{},参数信息",sceneName,executorName, JSONUtil.toJsonStr(objects)); + failOrderBaseMapper.delete( + new LambdaQueryChainWrapper<>(failOrderBaseMapper) + .eq(FailOrderPo::getOrderId,orderVo.getOrderId()) + ); + } + + /** + * 重试达到最大次数后的回调函数 + * 参数1-场景名称 + * 参数2-执行器名称 + * 参数3-入参信息 + */ + @Override + public void doMaxRetryCallback(String sceneName, String executorName, Object[] objects) { + OrderVo orderVo = (OrderVo) objects[0]; + log.info("远程重试达到最大限度,场景{},执行器{},参数信息",sceneName,executorName, JSONUtil.toJsonStr(objects)); + // 重试失败后插入订单失败信息 + failOrderBaseMapper.insert(FailOrderPo.builder() + .orderId(orderVo.getOrderId()) + .sourceId(orderVo.getSource()) + .sceneName(sceneName) + .executorName(executorName) + .args(JSONUtil.toJsonStr(objects)) + .build()); + } +} diff --git a/src/main/java/com/example/easy/retry/customized/OrderIdempotentIdGenerate.java b/src/main/java/com/example/easy/retry/customized/OrderIdempotentIdGenerate.java new file mode 100644 index 0000000..c08db6b --- /dev/null +++ b/src/main/java/com/example/easy/retry/customized/OrderIdempotentIdGenerate.java @@ -0,0 +1,21 @@ +package com.example.easy.retry.customized; + +import org.apache.catalina.security.SecurityUtil; + +import com.aizuda.easy.retry.client.core.IdempotentIdGenerate; +import com.aizuda.easy.retry.common.core.model.IdempotentIdContext; +import com.example.easy.retry.vo.OrderVo; + +import cn.hutool.crypto.SecureUtil; + + +public class OrderIdempotentIdGenerate implements IdempotentIdGenerate { + + @Override + public String idGenerate(IdempotentIdContext idempotentIdContext) throws Exception { + Object[] args = idempotentIdContext.getArgs(); + OrderVo orderVo = (OrderVo) args[0]; + return SecureUtil.md5(orderVo.getOrderId()); + } + +} diff --git a/src/main/java/com/example/easy/retry/customized/OrderRetryMethod.java b/src/main/java/com/example/easy/retry/customized/OrderRetryMethod.java new file mode 100644 index 0000000..158be30 --- /dev/null +++ b/src/main/java/com/example/easy/retry/customized/OrderRetryMethod.java @@ -0,0 +1,24 @@ +package com.example.easy.retry.customized; + +import java.lang.reflect.Array; + +import org.springframework.stereotype.Component; + +import com.aizuda.easy.retry.client.core.strategy.ExecutorMethod; +import com.example.easy.retry.vo.OrderVo; + +import cn.hutool.json.JSONUtil; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Component +public class OrderRetryMethod implements ExecutorMethod { + @Override + public Object doExecute(Object params) { + // 将特定类型的 Object 对象指定为 Object[] + Object[] args = (Object[]) params; + OrderVo orderVo = (OrderVo) args[0]; + log.info("进入指定自定义的异常处理类, 参数信息是{}", JSONUtil.toJsonStr(orderVo)); + throw new ArithmeticException("自定义的异常处理类处理"); + } +} diff --git a/src/main/java/com/example/easy/retry/customized/SingleParamIdempotentGenerate.java b/src/main/java/com/example/easy/retry/customized/SingleParamIdempotentGenerate.java new file mode 100644 index 0000000..a2f1dfd --- /dev/null +++ b/src/main/java/com/example/easy/retry/customized/SingleParamIdempotentGenerate.java @@ -0,0 +1,17 @@ +package com.example.easy.retry.customized; + +import com.aizuda.easy.retry.client.core.IdempotentIdGenerate; +import com.aizuda.easy.retry.common.core.model.IdempotentIdContext; +import com.example.easy.retry.vo.OrderVo; + +import cn.hutool.crypto.SecureUtil; + +public class SingleParamIdempotentGenerate implements IdempotentIdGenerate { + + @Override + public String idGenerate(IdempotentIdContext idempotentIdContext) throws Exception { + Object[] args = idempotentIdContext.getArgs(); + String params = (String) args[0]; + return SecureUtil.md5(params); + } +} diff --git a/src/main/java/com/example/easy/retry/dao/FailOrderBaseMapper.java b/src/main/java/com/example/easy/retry/dao/FailOrderBaseMapper.java new file mode 100644 index 0000000..ed4095f --- /dev/null +++ b/src/main/java/com/example/easy/retry/dao/FailOrderBaseMapper.java @@ -0,0 +1,11 @@ +package com.example.easy.retry.dao; + +import org.springframework.stereotype.Repository; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.example.easy.retry.po.FailOrderPo; + +@Repository +public interface FailOrderBaseMapper extends BaseMapper { + +} diff --git a/src/main/java/com/example/easy/retry/exception/BusinessException.java b/src/main/java/com/example/easy/retry/exception/BusinessException.java new file mode 100644 index 0000000..e40dff0 --- /dev/null +++ b/src/main/java/com/example/easy/retry/exception/BusinessException.java @@ -0,0 +1,12 @@ +package com.example.easy.retry.exception; + +/** + * 业务异常类 + */ +public class BusinessException extends RuntimeException{ + + public BusinessException(String message) { + super(message); + } + +} diff --git a/src/main/java/com/example/easy/retry/exception/ParamException.java b/src/main/java/com/example/easy/retry/exception/ParamException.java new file mode 100644 index 0000000..2d93671 --- /dev/null +++ b/src/main/java/com/example/easy/retry/exception/ParamException.java @@ -0,0 +1,10 @@ +package com.example.easy.retry.exception; +/** + * 参数异常处理类 + */ +public class ParamException extends BusinessException{ + public ParamException(String message) { + super(message); + } + +} diff --git a/src/main/java/com/example/easy/retry/executor/ManualRetryExecutorTask.java b/src/main/java/com/example/easy/retry/executor/ManualRetryExecutorTask.java new file mode 100644 index 0000000..8057729 --- /dev/null +++ b/src/main/java/com/example/easy/retry/executor/ManualRetryExecutorTask.java @@ -0,0 +1,26 @@ +package com.example.easy.retry.executor; + +import com.aizuda.easy.retry.client.core.annotation.ExecutorMethodRegister; +import com.aizuda.easy.retry.client.core.strategy.ExecutorMethod; +import com.example.easy.retry.vo.OrderVo; + +import cn.hutool.json.JSONUtil; +import lombok.extern.slf4j.Slf4j; + +@ExecutorMethodRegister(scene = ManualRetryExecutorTask.SCENE) +@Slf4j +public class ManualRetryExecutorTask implements ExecutorMethod { + /** + * 自定义场景值 + */ + public final static String SCENE = "manualRetry"; + + @Override + public Object doExecute(Object params) { + // 将特定类型的 Object 对象指定为 Object[] + Object[] args = (Object[]) params; + OrderVo orderVo = JSONUtil.toBean(JSONUtil.toJsonStr(args[0]), OrderVo.class); + log.info("进入手动重试方法,参数信息是{}", JSONUtil.toJsonStr(orderVo)); + return true; + } +} diff --git a/src/main/java/com/example/easy/retry/po/FailOrderPo.java b/src/main/java/com/example/easy/retry/po/FailOrderPo.java new file mode 100644 index 0000000..ec730c6 --- /dev/null +++ b/src/main/java/com/example/easy/retry/po/FailOrderPo.java @@ -0,0 +1,41 @@ +package com.example.easy.retry.po; + +import java.time.LocalDateTime; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 处理失败的订单信息表 + */ +@TableName("fail_order") +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class FailOrderPo { + + @TableId(value = "id", type = IdType.AUTO) + private Long id; + // 订单ID + private String orderId; + // 来源ID + private Integer sourceId; + // 场景名称 + private String sceneName; + // 执行器名称 + private String executorName; + // 参数信息 + private String args; + // 创建时间 + private LocalDateTime createDate; + // 更新时间 + private LocalDateTime updateDate; + +} diff --git a/src/main/java/com/example/easy/retry/service/LocalRemoteService.java b/src/main/java/com/example/easy/retry/service/LocalRemoteService.java new file mode 100644 index 0000000..f4fe7fa --- /dev/null +++ b/src/main/java/com/example/easy/retry/service/LocalRemoteService.java @@ -0,0 +1,36 @@ +package com.example.easy.retry.service; + +import com.aizuda.easy.retry.client.core.annotation.Retryable; +import com.aizuda.easy.retry.client.core.retryer.RetryType; +import org.springframework.stereotype.Service; + +import java.util.concurrent.TimeUnit; + +/** + * 模拟先本地再远程重试案例 + * + * @author www.byteblogs.com + * @date 2023-07-18 22:19:30 + * @since 2.1.0 + */ +@Service +public class LocalRemoteService { + + @Retryable(scene = "localRemote", retryStrategy = RetryType.LOCAL_REMOTE) + public void localRemote() { + System.out.println("local retry 方法开始执行"); + double i = 1 / 0; + } + + /** + * 使用先本地再远程的策略同步上传重试请求 retryStrategy = LOCAL_REMOTE 代表本地重试3次后再执行远程上报 async = false 代表使用同步上传的方式 timeout = 1 代表超时时间为1 + * unit = MINUTES 代表超时时间的单位是分钟 + */ + @Retryable(scene = "remoteRetryWithSync", retryStrategy = RetryType.LOCAL_REMOTE, + async = false, timeout = 1, unit = TimeUnit.MINUTES) + public String remoteRetryWithLocalRemote(String requestId) { + double i = 1 / 0; + return requestId; + } + +} diff --git a/src/main/java/com/example/easy/retry/service/LocalRetryService.java b/src/main/java/com/example/easy/retry/service/LocalRetryService.java new file mode 100644 index 0000000..8a5bd61 --- /dev/null +++ b/src/main/java/com/example/easy/retry/service/LocalRetryService.java @@ -0,0 +1,85 @@ +package com.example.easy.retry.service; + +import com.aizuda.easy.retry.client.core.retryer.RetryType; +import org.springframework.stereotype.Component; + +import com.aizuda.easy.retry.client.core.annotation.Retryable; +import com.example.easy.retry.exception.ParamException; + +/** + * easy-retry中的本地重试demo + * 测试类入口见 {@link com.example.easy.retry.local.RetryableTest} + */ + +@Component +public class LocalRetryService { + /** + * 入门案例 + * 我们仅仅需要指定场景值scene就可以给方法赋予重试逻辑 + * 其他的参数均可以省略或者使用默认值 + * [参数释义] + * 场景值scene对应我们后台的场景参数,用于后续的分组 + * 在微服务中建议大家直接使用集群的服务名称即可 + */ + @Retryable(scene = "localRetry", retryStrategy = RetryType.ONLY_LOCAL) + public void localRetry(String params) { + System.out.println("local retry 方法开始执行"); + double i = 1 / 0; + } + + /** + * 指定基础参数 + * localTimes 本地重试次数 + * localInterval 本地重试间隔时间(默认单位为秒) + * unit 超时时间单位 + * 以下案例指的是本地重试4次,每次重试之间间隔10s + */ + @Retryable(scene = "localRetryWithBasicParams", localTimes = 4, localInterval = 10, retryStrategy = RetryType.ONLY_LOCAL) + public void localRetryWithBasicParams(String params) { + System.out.println("local retry with basic params 方法开始执行"); + double i = 1 / 0; + } + + /** + * 指定异常参数 + * include参数指的是当我们遭遇到指定异常时进行重试 + * 在这个案例中我们处理两个场景: + * 抛出指定异常,例如抛出自定义的ParamException异常,观察是否会重试 + * 抛出非指定异常,例如我们在这里产生一个异常,观察是否会重试 + * 注意:如果此时我们在include 中指定参数为BusinessException(ParamException的父类),同样也会进行重试逻辑 + * 更多用法:如果我们需要在include中指定多个参数,可以使用 include = {ParamException.class,NullPointerException.class} + */ + @Retryable(scene = "localRetryIncludeException", include = ParamException.class, retryStrategy = RetryType.ONLY_LOCAL) + public void localRetryIncludeException(String params) { + System.out.println("local retry include exception 方法开始执行"); + if ("NullPointerException".equals(params)) { + throw new NullPointerException(); + } else { + throw new ParamException("此处发生了指定异常Param Exception"); + } + } + + /** + * 这个参数的作用和include是相反的 + * exclude参数指的是当我们遇到指定异常时则不会进行重试 + * 比如在下述案例中我们指定了遇到ParamException和ArithmeticException后不进行重试 + */ + @Retryable(scene = "localRetryExcludeException", exclude = {ParamException.class, ArithmeticException.class}, retryStrategy = RetryType.ONLY_LOCAL) + public void localRetryExcludeException(String type) { + System.out.println("local retry exclude exception 方法开始执行"); + + if ("ParamException".equals(type)) { + throw new ParamException("此处发生了指定异常Param Exception"); + } else if ("ArithmeticException".equals(type)) { + throw new ParamException("此处发生了指定异常Arithme Exception"); + } else { + throw new UnsupportedOperationException("未知异常"); + } + } + + @Retryable(scene = "localRetryIsThrowException", isThrowException = false, retryStrategy = RetryType.ONLY_LOCAL) + public void localRetryIsThrowException(String params) { + System.out.println("local retry is throw exception 方法开始执行"); + throw new ParamException("此处发生了参数异常"); + } +} diff --git a/src/main/java/com/example/easy/retry/service/ManualRetryExecutorMethodService.java b/src/main/java/com/example/easy/retry/service/ManualRetryExecutorMethodService.java new file mode 100644 index 0000000..e669170 --- /dev/null +++ b/src/main/java/com/example/easy/retry/service/ManualRetryExecutorMethodService.java @@ -0,0 +1,33 @@ +package com.example.easy.retry.service; + +import org.springframework.stereotype.Component; + +import com.aizuda.easy.retry.client.core.retryer.EasyRetryTemplate; +import com.aizuda.easy.retry.client.core.retryer.RetryTaskTemplateBuilder; +import com.example.easy.retry.executor.ManualRetryExecutorTask; +import com.example.easy.retry.vo.OrderVo; + +/** + * easy-retry中的手动重试 + */ +@Component +public class ManualRetryExecutorMethodService { + + public void myExecutorMethod(String params) { + OrderVo orderVo = OrderVo.builder() + .orderId(params) + .source(1) + .build(); + EasyRetryTemplate easyRetryTemplate = RetryTaskTemplateBuilder.newBuilder() + // 手动指定场景名称 + .withScene(ManualRetryExecutorTask.SCENE) + // 指定要执行的任务 + .withExecutorMethod(ManualRetryExecutorTask.class) + // 指定参数 + .withParam(orderVo) + .build(); + // 执行模板 + easyRetryTemplate.executeRetry(); + } + +} diff --git a/src/main/java/com/example/easy/retry/service/RemoteRetryService.java b/src/main/java/com/example/easy/retry/service/RemoteRetryService.java new file mode 100644 index 0000000..e12af86 --- /dev/null +++ b/src/main/java/com/example/easy/retry/service/RemoteRetryService.java @@ -0,0 +1,108 @@ +package com.example.easy.retry.service; + +import java.util.Random; +import java.util.concurrent.TimeUnit; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import com.aizuda.easy.retry.client.core.annotation.Retryable; +import com.aizuda.easy.retry.client.core.retryer.RetryType; +import com.example.easy.retry.customized.MultiParamIdempotentGenerate; +import com.example.easy.retry.customized.OrderIdempotentIdGenerate; +import com.example.easy.retry.customized.OrderCompleteCallback; +import com.example.easy.retry.customized.OrderRetryMethod; +import com.example.easy.retry.customized.SingleParamIdempotentGenerate; +import com.example.easy.retry.dao.FailOrderBaseMapper; +import com.example.easy.retry.po.FailOrderPo; +import com.example.easy.retry.vo.OrderVo; + +import cn.hutool.db.sql.Order; +import cn.hutool.json.JSONUtil; + +/** + * easy-retry中的远程重试 + */ +@Component +public class RemoteRetryService { + + /** + * 定义一个最基本的远程重试方法 + */ + @Retryable(scene = "remoteRetry", retryStrategy = RetryType.ONLY_REMOTE) + public void remoteRetry(String params) { + System.out.println("远程重试方法启动"); + double i = 1 / 0; + } + + @Retryable(scene = "remoteRetrySync", retryStrategy = RetryType.ONLY_REMOTE, async = false, timeout = 500, unit = TimeUnit.MILLISECONDS) + public void remoteSync(String params) { + System.out.println("同步远程重试方法启动"); + double i = 1 / 0; + } + + /** + * 使用自定义的幂等Id生成类 OrderIdempotentIdGenerate + */ + @Retryable(scene = "remoteRetryWithIdempotentId", retryStrategy = RetryType.ONLY_REMOTE, + idempotentId = OrderIdempotentIdGenerate.class) + public boolean remoteRetryWithIdempotentId(OrderVo orderVo) { + double i = 1 / 0; + return true; + } + + /** + * 使用自定义的幂等Id生成类 SingleParamIdempotentGenerate 测试单参数场景下 + */ + @Retryable(scene = "retryWithSingleParamIdempotentGenerate", retryStrategy = RetryType.ONLY_REMOTE, + idempotentId = SingleParamIdempotentGenerate.class) + public boolean retryWithSingleParamIdempotentGenerate(String params) { + throw new NullPointerException(); + } + + /** + * 使用自定义的幂等Id生成类 MultiParamIdempotentGenerate 测试多个参数场景下的解析 + */ + @Retryable(scene = "retryWithMulParamIdempotentGenerate", retryStrategy = RetryType.ONLY_REMOTE, + idempotentId = MultiParamIdempotentGenerate.class) + public boolean retryWithMulParamIdempotentGenerate(String uuid, Integer intVal, Double doubleVal, + Character character, OrderVo orderVo) { + throw new NullPointerException(); + } + + /** + * 使用自定义的异常处理类 OrderRetryMethod + */ + @Retryable(scene = "remoteRetryWithRetryMethod", retryStrategy = RetryType.ONLY_REMOTE, + retryMethod = OrderRetryMethod.class) + public boolean remoteRetryWithRetryMethod(OrderVo orderVo) { + throw new NullPointerException(); + } + + /** + * 使用自定义的retryCompleteCallback类 OrderCompleteCallback + */ + @Retryable(scene = "remoteRetryWithCompleteCallback", retryStrategy = RetryType.LOCAL_REMOTE, + retryCompleteCallback = OrderCompleteCallback.class) + public boolean remoteRetryWithCompleteCallback(OrderVo orderVo) { + Random random = new Random(); + // 生成一个随机数,范围为0到1之间 + double probability = random.nextDouble(); + // 判断随机数是否小于等于0.5,即50%的概率 + if (probability <= 0.5) { + // 生成的结果在50%的概率下执行这里的逻辑 + throw new NullPointerException(); + } + return true; + } + + /** + * 自定义BizNo + */ + @Retryable(scene = "remoteRetryWithBizNo", retryStrategy = RetryType.ONLY_REMOTE, bizNo = "#orderVo.orderId") + public boolean remoteRetryWithBizNo(OrderVo orderVo) { + throw new NullPointerException(); + } + + +} diff --git a/src/main/java/com/example/easy/retry/spi/MyEasyRetryListener.java b/src/main/java/com/example/easy/retry/spi/MyEasyRetryListener.java new file mode 100644 index 0000000..90fd09b --- /dev/null +++ b/src/main/java/com/example/easy/retry/spi/MyEasyRetryListener.java @@ -0,0 +1,30 @@ +package com.example.easy.retry.spi; + +import com.aizuda.easy.retry.client.core.event.EasyRetryListener; +import com.aizuda.easy.retry.common.core.util.JsonUtil; +import lombok.extern.slf4j.Slf4j; + +/** + * @author: www.byteblogs.com + * @date : 2023-08-28 11:20 + */ +@Slf4j +public class MyEasyRetryListener implements EasyRetryListener { + + @Override + public void beforeRetry(final String sceneName, final String executorClassName, final Object[] params) { + log.info("------> beforeRetry sceneName:[{}] executorClassName:[{}] params:[{}]", + sceneName, executorClassName, JsonUtil.toJsonString(params)); + } + + @Override + public void successOnRetry(final Object result, final String sceneName, final String executorClassName) { + log.info("------> successOnRetry sceneName:[{}] executorClassName:[{}] result:[{}]", + sceneName, executorClassName, JsonUtil.toJsonString(result)); + } + + @Override + public void failureOnRetry(final String sceneName, final String executorClassName, final Throwable e) { + log.info("------> failureOnRetry sceneName:[{}] executorClassName:[{}]", sceneName, executorClassName, e); + } +} diff --git a/src/main/java/com/example/easy/retry/spi/TTLRetrySiteSnapshotContext.java b/src/main/java/com/example/easy/retry/spi/TTLRetrySiteSnapshotContext.java new file mode 100644 index 0000000..9627171 --- /dev/null +++ b/src/main/java/com/example/easy/retry/spi/TTLRetrySiteSnapshotContext.java @@ -0,0 +1,32 @@ +package com.example.easy.retry.spi; + +import com.aizuda.easy.retry.client.core.RetrySiteSnapshotContext; +import com.alibaba.ttl.TransmittableThreadLocal; + +/** + * @author: www.byteblogs.com + * @date : 2023-08-28 11:30 + */ +public class TTLRetrySiteSnapshotContext implements RetrySiteSnapshotContext { + + private final ThreadLocal threadLocal; + + public TTLRetrySiteSnapshotContext() { + this.threadLocal = new TransmittableThreadLocal<>(); + } + + @Override + public void set(final T value) { + threadLocal.set(value); + } + + @Override + public void remove() { + threadLocal.remove(); + } + + @Override + public T get() { + return threadLocal.get(); + } +} diff --git a/src/main/java/com/example/easy/retry/util/CodeGen.java b/src/main/java/com/example/easy/retry/util/CodeGen.java new file mode 100644 index 0000000..f32fd3c --- /dev/null +++ b/src/main/java/com/example/easy/retry/util/CodeGen.java @@ -0,0 +1,52 @@ +package com.example.easy.retry.util; + +import org.springframework.beans.factory.annotation.Value; + +import com.baomidou.mybatisplus.generator.AutoGenerator; +import com.baomidou.mybatisplus.generator.config.DataSourceConfig; +import com.baomidou.mybatisplus.generator.config.GlobalConfig; +import com.baomidou.mybatisplus.generator.config.PackageConfig; +import com.baomidou.mybatisplus.generator.config.StrategyConfig; + +public class CodeGen { + + @Value("${spring.datasource.url}") + private static String dataSourceUrl; + + @Value("${spring.datasource.username}") + private static String userName; + + @Value("${spring.datasource.password}") + private static String password; + + public static void main(String[] args) { + DataSourceConfig dataSourceConfig = new DataSourceConfig.Builder(dataSourceUrl, userName, password).build(); + + // 全局配置 + GlobalConfig globalConfig = new GlobalConfig.Builder() + .outputDir("src/main/java") + .author("maluxinyu") + .build(); + + // 策略配置 + StrategyConfig strategyConfig = new StrategyConfig.Builder() + .addInclude("fail_order") // 需要生成的表名 + .build(); + + // 包配置 + PackageConfig packageConfig = new PackageConfig.Builder() + .parent("com.maluxinyu.easyretry") + .moduleName("easy-retry-springboot") + .build(); + + // 代码生成器 + AutoGenerator generator = new AutoGenerator(dataSourceConfig) + .global(globalConfig) + .strategy(strategyConfig) + .packageInfo(packageConfig); + + // 执行生成代码 + generator.execute(); + + } +} diff --git a/src/main/java/com/example/easy/retry/vo/OrderVo.java b/src/main/java/com/example/easy/retry/vo/OrderVo.java new file mode 100644 index 0000000..9320692 --- /dev/null +++ b/src/main/java/com/example/easy/retry/vo/OrderVo.java @@ -0,0 +1,22 @@ +package com.example.easy.retry.vo; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.List; + +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class OrderVo { + @ApiModelProperty(value = "订单ID,用于唯一标识订单的编号", required = true) + private String orderId; // 订单ID,用于唯一标识订单的编号 + @ApiModelProperty(value = "订单来源信息,1-手机端下单 2-PC端下单",required = true) + private Integer source; // 订单来源信息,1-手机端下单 2-PC端下单 +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml new file mode 100644 index 0000000..7752cb6 --- /dev/null +++ b/src/main/resources/application.yml @@ -0,0 +1,44 @@ +server: + port: 8018 +spring: + mvc: + pathmatch: + matching-strategy: ant_path_matcher + profiles: + active: dev + datasource: + name: easy_retry + url: jdbc:mysql://localhost:3306/demo?useSSL=false&characterEncoding=utf8&useUnicode=true + username: root + password: root + type: com.zaxxer.hikari.HikariDataSource + driver-class-name: com.mysql.cj.jdbc.Driver + hikari: + connection-timeout: 30000 + minimum-idle: 5 + maximum-pool-size: 20 + auto-commit: true + idle-timeout: 30000 + pool-name: demo + max-lifetime: 1800000 + connection-test-query: SELECT 1 +mybatis-plus: + mapper-locations: classpath:/mapper/*.xml + typeAliasesPackage: com.example.easy.retry.po + global-config: + db-config: + field-strategy: NOT_EMPTY + capital-mode: false + logic-delete-value: 1 + logic-not-delete-value: 0 + configuration: + map-underscore-to-camel-case: true + cache-enabled: true + +logging: + config: classpath:logback-boot.xml + +easy-retry: + server: + host: 127.0.0.1 + port: 1788 diff --git a/src/main/resources/logback-boot.xml b/src/main/resources/logback-boot.xml new file mode 100644 index 0000000..ebb1737 --- /dev/null +++ b/src/main/resources/logback-boot.xml @@ -0,0 +1,88 @@ + + + + + + + %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{256} - %msg%n + + + + + + ./data/log/${log.base}/info/info.log + + ./data/log/${log.base}/info/info.%d{yyyy-MM-dd}.log + 30 + + + %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{256} - %msg%n + + + INFO + ACCEPT + DENY + + + + + ./data/log/${log.base}/warn/warn.log + + ./data/log/${log.base}/warn/warn.%d{yyyy-MM-dd}.log + + 30 + + + %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{256} - %msg%n + + + WARN + ACCEPT + DENY + + + + + ./data/log/${log.base}/error/error.log + + ./data/log/${log.base}/error/error.%d{yyyy-MM-dd}.log + + 30 + + + %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{256} - %msg%n + + + ERROR + ACCEPT + DENY + + + + + 100 + 1024 + + + + + 100 + 1024 + + + + + 100 + 1024 + + + + + + + + + + + diff --git a/src/main/resources/services/com.aizuda.easy.retry.client.core.RetryArgSerializer b/src/main/resources/services/com.aizuda.easy.retry.client.core.RetryArgSerializer new file mode 100644 index 0000000..30c4ca4 --- /dev/null +++ b/src/main/resources/services/com.aizuda.easy.retry.client.core.RetryArgSerializer @@ -0,0 +1,2 @@ +#com.aizuda.easy.retry.client.core.serializer.HessianSerializer +#com.aizuda.easy.retry.client.core.serializer.JacksonSerializer diff --git a/src/main/resources/services/com.aizuda.easy.retry.client.core.RetrySiteSnapshotContext b/src/main/resources/services/com.aizuda.easy.retry.client.core.RetrySiteSnapshotContext new file mode 100644 index 0000000..f8d0216 --- /dev/null +++ b/src/main/resources/services/com.aizuda.easy.retry.client.core.RetrySiteSnapshotContext @@ -0,0 +1 @@ +#com.maluxinyu.easyretry.spi.TTLRetrySiteSnapshotContext diff --git a/src/main/resources/services/com.aizuda.easy.retry.client.core.event.EasyRetryListener b/src/main/resources/services/com.aizuda.easy.retry.client.core.event.EasyRetryListener new file mode 100644 index 0000000..6837c1d --- /dev/null +++ b/src/main/resources/services/com.aizuda.easy.retry.client.core.event.EasyRetryListener @@ -0,0 +1 @@ +#com.maluxinyu.easyretry.spi.MyEasyRetryListener