修复重试锁死问题

This commit is contained in:
byteblogs168 2023-01-14 19:56:12 +08:00
parent 2305ad070f
commit 4c0c9175ed
44 changed files with 228 additions and 103 deletions

View File

@ -67,18 +67,74 @@ public class ExampleApplication {
| localTimes |int|是|3| 本地重试次数 次数必须大于等于1|
| localInterval |int|是|2| 本地重试间隔时间(s)|
## 初始化数据库
## 配置部署服务端调度平台
### 初始化数据库
数据库脚本位置
```
doc/sql/x_retry.sql
```
## 配置部署服务端调度平台
### 系统配置
```yaml
spring:
datasource:
name: x_retry
url: jdbc:mysql://localhost:3306/x_retry?useSSL=false&characterEncoding=utf8&useUnicode=true
username: root
password: root
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.jdbc.Driver
hikari:
connection-timeout: 30000
minimum-idle: 5
maximum-pool-size: 20
auto-commit: true
idle-timeout: 30000
pool-name: x_retry
max-lifetime: 1800000
connection-test-query: SELECT 1
resources:
static-locations: classpath:admin/
mybatis-plus:
mapper-locations: classpath:/mapper/*.xml
typeAliasesPackage: com.x.retry.server.persistence.mybatis.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
x-retry:
lastDays: 30 # 拉取重试数据的天数
retryPullPageSize: 100 # 拉取重试数据的每批次的大小
nettyPort: 1788 # 服务端netty端口
totalPartition: 32 # 重试和死信表的分区总数
### 组列表
```
##项目部署
如果你已经正确按照系统了,那么你可以输入
```
http://localhost:8080
```
会出现登陆页面:
![img.png](images/login.png)
输入用户名: admin, 密码: 123456
## 组配置
通过`新建`按钮配置点开配置组、场景、通知界面
![group_list.png](./images/group_list.png)
### 组配置
组名称: 名称是数字、字母、下划线组合最长64个字符长度
状态: 开启/关闭, 通过状态开启或关闭组状态
路由策略:
描述:
知道分区 :
![goup_config.png](./images/goup_config.png)
### 场景配置

BIN
doc/images/login.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

View File

@ -0,0 +1,54 @@
package com.example.demo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.example.mapper.SchoolMapper;
import com.example.mapper.StudentMapper;
import com.example.po.School;
import com.example.po.Student;
import com.x.retry.client.core.annotation.Retryable;
import com.x.retry.common.core.model.Result;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.util.UUID;
/**
* @author: www.byteblogs.com
* @date : 2022-03-26 09:08
*/
@Component
public class TestExistsTransactionalRetryService2 {
@Autowired
private SchoolMapper schoolMapper;
@Autowired
private StudentMapper studentMapper;
@Autowired
private RemoteService remoteService;
@Retryable(scene = "testSimpleUpdate", bizNo = "#name", localTimes = 5)
@Transactional
public String testSimpleUpdate(Long id) {
School school = new School();
school.setAddress(UUID.randomUUID().toString());
school.setCreateDt(LocalDateTime.now());
school.setUpdateDt(LocalDateTime.now());
schoolMapper.update(school, new LambdaQueryWrapper<School>()
.eq(School::getId, id));
Result call = remoteService.call();
System.out.println("-------------->"+call.getMessage());
if (call.getStatus() == 0) {
throw new UnsupportedOperationException("调用远程失败");
}
return "testSimpleInsert"+school.getAddress();
}
}

View File

@ -36,4 +36,6 @@ mybatis-plus:
logging:
config: classpath:logback-boot.xml
x-retry:
server:
host: 192.168.100.3

View File

@ -2,6 +2,7 @@ package com.example;
import com.example.demo.RemoteService;
import com.example.demo.TestExistsTransactionalRetryService;
import com.example.demo.TestExistsTransactionalRetryService2;
import com.x.retry.common.core.model.Result;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
@ -27,6 +28,8 @@ public class ExistsTransactionalRetryServiceTest {
private TestExistsTransactionalRetryService testExistsTransactionalRetryService;
@MockBean
private RemoteService remoteService;
@Autowired
private TestExistsTransactionalRetryService2 testExistsTransactionalRetryService2;
@SneakyThrows
@Test
@ -35,7 +38,7 @@ public class ExistsTransactionalRetryServiceTest {
Mockito.when(remoteService.call())
.thenReturn(new Result(0, "1"))
.thenReturn(new Result(0, "2"))
.thenReturn(new Result(0, "3"))
.thenReturn(new Result(1, "3"))
.thenReturn(new Result(0, "4"))
.thenReturn(new Result(0, "5"))
;
@ -50,4 +53,26 @@ public class ExistsTransactionalRetryServiceTest {
Thread.sleep(90000);
}
@SneakyThrows
@Test
public void testSimpleUpdate() {
Mockito.when(remoteService.call())
.thenReturn(new Result(0, "1"))
.thenReturn(new Result(0, "2"))
.thenReturn(new Result(0, "3"))
.thenReturn(new Result(0, "4"))
.thenReturn(new Result(0, "5"))
;
try {
String s = testExistsTransactionalRetryService2.testSimpleUpdate(243L);
System.out.println(s);
} catch (Exception e) {
log.error("", e);
}
Thread.sleep(90000);
}
}

View File

@ -22,7 +22,7 @@ export default {
'layouts.usermenu.dialog.title': 'Message',
'layouts.usermenu.dialog.content': 'Are you sure you would like to logout?',
'layouts.userLayout.title': 'Ant Design is the most influential web design specification in Xihu district',
'layouts.userLayout.title': 'Easy to use distributed exception retry service platform',
...components,
...global,
...menu,

View File

@ -1,8 +1,8 @@
export default {
'user.login.userName': 'userName',
'user.login.password': 'password',
'user.login.username.placeholder': 'Account: admin',
'user.login.password.placeholder': 'password: admin or ant.design',
'user.login.username.placeholder': 'Please enter the username',
'user.login.password.placeholder': 'Please enter the password',
'user.login.message-invalid-credentials':
'Invalid username or password',
'user.login.message-invalid-verification-code': 'Invalid verification code',

View File

@ -21,7 +21,7 @@ export default {
'layouts.usermenu.dialog.title': '信息',
'layouts.usermenu.dialog.content': '您确定要注销吗?',
'layouts.userLayout.title': 'Ant Design 是西湖区最具影响力的 Web 设计规范',
'layouts.userLayout.title': '简单易用的分布式异常重试服务平台',
...components,
...global,
...menu,

View File

@ -1,8 +1,8 @@
export default {
'user.login.userName': '用户名',
'user.login.password': '密码',
'user.login.username.placeholder': '账户: admin',
'user.login.password.placeholder': '密码: admin or ant.design',
'user.login.username.placeholder': '请输入账号',
'user.login.password.placeholder': '请输入密码',
'user.login.message-invalid-credentials': '账户或密码错误',
'user.login.message-invalid-verification-code': '验证码错误',
'user.login.tab-login-credentials': '账户密码登录',

View File

@ -1,43 +0,0 @@
package com.x.retry.client.core.init;
import com.x.retry.client.core.Scanner;
import com.x.retry.client.core.config.XRetryProperties;
import com.x.retry.client.core.register.RetryableRegistrar;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* @author: www.byteblogs.com
* @date : 2022-03-03 16:50
*/
@Component
@Slf4j
public class RetryInitialize implements SmartInitializingSingleton, ApplicationContextAware {
@Autowired
private List<Scanner> scanners;
@Autowired
private RetryableRegistrar retryableRegistrar;
@Autowired
private XRetryProperties xRetryProperties;
@Override
public void afterSingletonsInstantiated() {
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
}
}

View File

@ -15,6 +15,9 @@ import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.transaction.support.TransactionTemplate;
import java.lang.reflect.Method;
import java.util.Objects;
@ -32,12 +35,14 @@ public class RetryAspect {
@Autowired
@Qualifier("localRetryStrategies")
private RetryStrategy retryStrategy;
@Autowired(required = false)
private TransactionTemplate transactionTemplate;
@Around("@annotation(com.x.retry.client.core.annotation.Retryable)")
public Object around(ProceedingJoinPoint point) throws Throwable {
String traceId = UUID.randomUUID().toString();
LogUtils.debug("进入 aop [{}]",traceId);
LogUtils.debug("进入 aop [{}]", traceId);
Retryable retryable = getAnnotationParameter(point);
String executorClassName = point.getTarget().getClass().getName();
String methodEntrance = getMethodEntrance(retryable, executorClassName);
@ -53,26 +58,12 @@ public class RetryAspect {
throwable = t;
} finally {
if (RetrySiteSnapshot.isMethodEntrance(methodEntrance) && !RetrySiteSnapshot.isRunning() && Objects.nonNull(throwable)) {
LogUtils.debug("开始进行重试 aop [{}]", traceId);
try {
// 入口则开始处理重试
RetryerResultContext context = retryStrategy.openRetry(retryable.scene(), executorClassName, point.getArgs());
if (RetryResultStatusEnum.SUCCESS.getStatus().equals(context.getRetryResultStatusEnum().getStatus())) {
LogUtils.debug("aop 结果成功 traceId:[{}] result:[{}]", traceId, context.getResult());
}
} catch (Exception e) {
LogUtils.error("重试组件处理异常,{}", e);
// TODO调用通知
} finally {
RetrySiteSnapshot.removeAll();
}
}
LogUtils.debug("开始进行重试 aop [{}]", traceId);
// 入口则开始处理重试
doHandlerRetry(point, traceId, retryable, executorClassName, methodEntrance, throwable);
}
LogUtils.debug("aop 结果处理 traceId:[{}] result:[{}] ", traceId, result, throwable);
LogUtils.debug("aop 结果处理 traceId:[{}] result:[{}] ", traceId, result, throwable);
if (throwable != null) {
throw throwable;
} else {
@ -81,6 +72,47 @@ public class RetryAspect {
}
private void doHandlerRetry(ProceedingJoinPoint point, String traceId, Retryable retryable, String executorClassName, String methodEntrance, Throwable throwable) {
if (!RetrySiteSnapshot.isMethodEntrance(methodEntrance) || RetrySiteSnapshot.isRunning() || Objects.isNull(throwable)) {
return;
}
if (!TransactionSynchronizationManager.isActualTransactionActive()) {
// 无事务, 开启重试
openRetry(point, traceId, retryable, executorClassName);
return;
}
// 存在事物
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
@Override
public void afterCompletion(int status) {
if (STATUS_ROLLED_BACK == status) {
// 有事务开启重试
openRetry(point, traceId, retryable, executorClassName);
}
}
});
}
private void openRetry(ProceedingJoinPoint point, String traceId, Retryable retryable, String executorClassName) {
try {
RetryerResultContext context = retryStrategy.openRetry(retryable.scene(), executorClassName, point.getArgs());
if (RetryResultStatusEnum.SUCCESS.getStatus().equals(context.getRetryResultStatusEnum().getStatus())) {
LogUtils.debug("aop 结果成功 traceId:[{}] result:[{}]", traceId, context.getResult());
}
} catch (Exception e) {
LogUtils.error("重试组件处理异常,{}", e);
// TODO调用通知
} finally {
RetrySiteSnapshot.removeAll();
}
}
public String getMethodEntrance(Retryable retryable, String executorClassName) {
if (Objects.isNull(retryable)) {

View File

@ -18,4 +18,6 @@ public class RetryerResultContext {
private String message;
private Throwable throwable;
}

View File

@ -93,7 +93,7 @@ public abstract class AbstractRetryStrategies implements RetryStrategy {
private Consumer<Throwable> getRetryErrorConsumer(RetryerResultContext context, Object... params) {
return throwable -> {
context.setThrowable(throwable);
context.setMessage(throwable.getMessage());
error(context);

View File

@ -9,5 +9,4 @@ EXPOSE 1788
WORKDIR /
#开机启动
ENTRYPOINT ["java","-jar","x-retry-server.jar"]
ENTRYPOINT ["sh","-c","java -jar $JAVA_OPTS /x-retry-server.jar $PARAMS"]

View File

@ -1,6 +1,7 @@
package com.x.retry.server.support.dispatch.actor.result;
import akka.actor.AbstractActor;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.x.retry.common.core.enums.RetryStatusEnum;
import com.x.retry.common.core.log.LogUtils;
import com.x.retry.common.core.util.Assert;
@ -60,9 +61,6 @@ public class FailureActor extends AbstractActor {
retryTask.setRetryStatus(RetryStatusEnum.MAX_RETRY_COUNT.getLevel());
}
RetryTaskLog retryTaskLog = new RetryTaskLog();
retryTaskLog.setErrorMessage(StringUtils.EMPTY);
try {
retryTaskAccess.updateRetryTask(retryTask);
} catch (Exception e) {
@ -71,11 +69,11 @@ public class FailureActor extends AbstractActor {
getContext().stop(getSelf());
// 记录重试日志
BeanUtils.copyProperties(retryTask, retryTaskLog);
retryTaskLog.setCreateDt(LocalDateTime.now());
retryTaskLog.setId(null);
Assert.isTrue(1 == retryTaskLogMapper.insert(retryTaskLog),
new XRetryServerException("重试日志失败"));
RetryTaskLog retryTaskLog = new RetryTaskLog();
retryTaskLog.setRetryStatus(retryTask.getRetryStatus());
Assert.isTrue(1 == retryTaskLogMapper.update(retryTaskLog,
new LambdaQueryWrapper<RetryTaskLog>().eq(RetryTaskLog::getBizId, retryTask.getBizId())),
new XRetryServerException("新重试日志失败"));
}
}).build();

View File

@ -49,8 +49,6 @@ public class FinishActor extends AbstractActor {
retryTask.setRetryStatus(RetryStatusEnum.FINISH.getLevel());
RetryTaskLog retryTaskLog = new RetryTaskLog();
retryTaskLog.setErrorMessage(StringUtils.EMPTY);
try {
retryTaskAccess.updateRetryTask(retryTask);
@ -61,11 +59,11 @@ public class FinishActor extends AbstractActor {
getContext().stop(getSelf());
// 记录重试日志
BeanUtils.copyProperties(retryTask, retryTaskLog);
retryTaskLog.setCreateDt(LocalDateTime.now());
retryTaskLog.setId(null);
Assert.isTrue(1 == retryTaskLogMapper.insert(retryTaskLog),
new XRetryServerException("重试日志失败"));
RetryTaskLog retryTaskLog = new RetryTaskLog();
retryTaskLog.setRetryStatus(retryTask.getRetryStatus());
Assert.isTrue(1 == retryTaskLogMapper.update(retryTaskLog,
new LambdaQueryWrapper<RetryTaskLog>().eq(RetryTaskLog::getBizId, retryTask.getBizId())),
new XRetryServerException("新重试日志失败"));
}

View File

@ -1 +1 @@
<!DOCTYPE html><html lang="zh-cmn-Hans"><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" href="/logo.png"><title>X-RETRY</title><style>.first-loading-wrp{display:flex;justify-content:center;align-items:center;flex-direction:column;min-height:420px;height:100%}.first-loading-wrp>h1{font-size:128px}.first-loading-wrp .loading-wrp{padding:98px;display:flex;justify-content:center;align-items:center}.dot{animation:antRotate 1.2s infinite linear;transform:rotate(45deg);position:relative;display:inline-block;font-size:32px;width:32px;height:32px;box-sizing:border-box}.dot i{width:14px;height:14px;position:absolute;display:block;background-color:#1890ff;border-radius:100%;transform:scale(.75);transform-origin:50% 50%;opacity:.3;animation:antSpinMove 1s infinite linear alternate}.dot i:nth-child(1){top:0;left:0}.dot i:nth-child(2){top:0;right:0;-webkit-animation-delay:.4s;animation-delay:.4s}.dot i:nth-child(3){right:0;bottom:0;-webkit-animation-delay:.8s;animation-delay:.8s}.dot i:nth-child(4){bottom:0;left:0;-webkit-animation-delay:1.2s;animation-delay:1.2s}@keyframes antRotate{to{-webkit-transform:rotate(405deg);transform:rotate(405deg)}}@-webkit-keyframes antRotate{to{-webkit-transform:rotate(405deg);transform:rotate(405deg)}}@keyframes antSpinMove{to{opacity:1}}@-webkit-keyframes antSpinMove{to{opacity:1}}</style><link href="/css/chunk-1ab37f3c.3d18d222.css" rel="prefetch"><link href="/css/chunk-25728828.1a0c6d40.css" rel="prefetch"><link href="/css/chunk-7da4eb58.e728df71.css" rel="prefetch"><link href="/css/chunk-8b6319a2.2634f734.css" rel="prefetch"><link href="/css/user.6ccd4506.css" rel="prefetch"><link href="/js/chunk-182ca22a.03fcf245.js" rel="prefetch"><link href="/js/chunk-1ab37f3c.8de58c12.js" rel="prefetch"><link href="/js/chunk-2187724d.750eefe4.js" rel="prefetch"><link href="/js/chunk-2515aa86.56b830ae.js" rel="prefetch"><link href="/js/chunk-25728828.72403b96.js" rel="prefetch"><link href="/js/chunk-2672acfa.f21ce0e0.js" rel="prefetch"><link href="/js/chunk-35f6c8ac.ba9dc4ea.js" rel="prefetch"><link href="/js/chunk-3f8d11fc.0a406521.js" rel="prefetch"><link href="/js/chunk-7da4eb58.42370445.js" rel="prefetch"><link href="/js/chunk-8b6319a2.ce4381a7.js" rel="prefetch"><link href="/js/chunk-a31b7d0a.26cf2cba.js" rel="prefetch"><link href="/js/chunk-c70de2f6.079cc723.js" rel="prefetch"><link href="/js/chunk-f6267108.805d13c0.js" rel="prefetch"><link href="/js/fail.2fbe761d.js" rel="prefetch"><link href="/js/lang-zh-CN-account-settings.c67af352.js" rel="prefetch"><link href="/js/lang-zh-CN-account.ae001550.js" rel="prefetch"><link href="/js/lang-zh-CN-dashboard-analysis.2fc3e69f.js" rel="prefetch"><link href="/js/lang-zh-CN-dashboard.99f39538.js" rel="prefetch"><link href="/js/lang-zh-CN-form-basicForm.2de7abab.js" rel="prefetch"><link href="/js/lang-zh-CN-form.827c727b.js" rel="prefetch"><link href="/js/lang-zh-CN-global.2ab19788.js" rel="prefetch"><link href="/js/lang-zh-CN-menu.3e33ed30.js" rel="prefetch"><link href="/js/lang-zh-CN-result-fail.e3747840.js" rel="prefetch"><link href="/js/lang-zh-CN-result-success.349556c5.js" rel="prefetch"><link href="/js/lang-zh-CN-result.ae8b0e63.js" rel="prefetch"><link href="/js/lang-zh-CN-setting.78d9e9d1.js" rel="prefetch"><link href="/js/lang-zh-CN-user.f0b0e0c8.js" rel="prefetch"><link href="/js/lang-zh-CN.d4df1883.js" rel="prefetch"><link href="/js/user.5bc5ffe1.js" rel="prefetch"><link href="/css/app.7dac075b.css" rel="preload" as="style"><link href="/css/chunk-vendors.f716a607.css" rel="preload" as="style"><link href="/js/app.fbb09a18.js" rel="preload" as="script"><link href="/js/chunk-vendors.7a131374.js" rel="preload" as="script"><link href="/css/chunk-vendors.f716a607.css" rel="stylesheet"><link href="/css/app.7dac075b.css" rel="stylesheet"></head><body><noscript><strong>We're sorry but vue-antd-pro doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"><div class="first-loading-wrp"><h1>X-RETRY</h1><div class="loading-wrp"><span class="dot dot-spin"><i></i><i></i><i></i><i></i></span></div><div style="display: flex; justify-content: center; align-items: center;">X-RETRY</div></div></div><script src="//cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.min.js"></script><script src="//cdn.jsdelivr.net/npm/vue-router@3.5.1/dist/vue-router.min.js"></script><script src="//cdn.jsdelivr.net/npm/vuex@3.1.1/dist/vuex.min.js"></script><script src="//cdn.jsdelivr.net/npm/axios@0.21.1/dist/axios.min.js"></script><script src="/js/chunk-vendors.7a131374.js"></script><script src="/js/app.fbb09a18.js"></script></body></html>
<!DOCTYPE html><html lang="zh-cmn-Hans"><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" href="/logo.png"><title>X-RETRY</title><style>.first-loading-wrp{display:flex;justify-content:center;align-items:center;flex-direction:column;min-height:420px;height:100%}.first-loading-wrp>h1{font-size:128px}.first-loading-wrp .loading-wrp{padding:98px;display:flex;justify-content:center;align-items:center}.dot{animation:antRotate 1.2s infinite linear;transform:rotate(45deg);position:relative;display:inline-block;font-size:32px;width:32px;height:32px;box-sizing:border-box}.dot i{width:14px;height:14px;position:absolute;display:block;background-color:#1890ff;border-radius:100%;transform:scale(.75);transform-origin:50% 50%;opacity:.3;animation:antSpinMove 1s infinite linear alternate}.dot i:nth-child(1){top:0;left:0}.dot i:nth-child(2){top:0;right:0;-webkit-animation-delay:.4s;animation-delay:.4s}.dot i:nth-child(3){right:0;bottom:0;-webkit-animation-delay:.8s;animation-delay:.8s}.dot i:nth-child(4){bottom:0;left:0;-webkit-animation-delay:1.2s;animation-delay:1.2s}@keyframes antRotate{to{-webkit-transform:rotate(405deg);transform:rotate(405deg)}}@-webkit-keyframes antRotate{to{-webkit-transform:rotate(405deg);transform:rotate(405deg)}}@keyframes antSpinMove{to{opacity:1}}@-webkit-keyframes antSpinMove{to{opacity:1}}</style><link href="/css/chunk-1ab37f3c.3d18d222.css" rel="prefetch"><link href="/css/chunk-25728828.1a0c6d40.css" rel="prefetch"><link href="/css/chunk-7da4eb58.e728df71.css" rel="prefetch"><link href="/css/chunk-8b6319a2.2634f734.css" rel="prefetch"><link href="/css/user.6ccd4506.css" rel="prefetch"><link href="/js/chunk-182ca22a.8c34614c.js" rel="prefetch"><link href="/js/chunk-1ab37f3c.6610a799.js" rel="prefetch"><link href="/js/chunk-2187724d.5ce67d3e.js" rel="prefetch"><link href="/js/chunk-2515aa86.e77b4462.js" rel="prefetch"><link href="/js/chunk-25728828.58065cc5.js" rel="prefetch"><link href="/js/chunk-2672acfa.a463d565.js" rel="prefetch"><link href="/js/chunk-35f6c8ac.0e2089f4.js" rel="prefetch"><link href="/js/chunk-3f8d11fc.36654171.js" rel="prefetch"><link href="/js/chunk-7da4eb58.f8e4729e.js" rel="prefetch"><link href="/js/chunk-8b6319a2.08c27435.js" rel="prefetch"><link href="/js/chunk-a31b7d0a.583cee66.js" rel="prefetch"><link href="/js/chunk-c70de2f6.c1b55ec1.js" rel="prefetch"><link href="/js/chunk-f6267108.b893984c.js" rel="prefetch"><link href="/js/fail.a308c208.js" rel="prefetch"><link href="/js/lang-zh-CN-account-settings.c67af352.js" rel="prefetch"><link href="/js/lang-zh-CN-account.31178b83.js" rel="prefetch"><link href="/js/lang-zh-CN-dashboard-analysis.2fc3e69f.js" rel="prefetch"><link href="/js/lang-zh-CN-dashboard.8c2660f7.js" rel="prefetch"><link href="/js/lang-zh-CN-form-basicForm.2de7abab.js" rel="prefetch"><link href="/js/lang-zh-CN-form.9e72dbc7.js" rel="prefetch"><link href="/js/lang-zh-CN-global.2ab19788.js" rel="prefetch"><link href="/js/lang-zh-CN-menu.3e33ed30.js" rel="prefetch"><link href="/js/lang-zh-CN-result-fail.e3747840.js" rel="prefetch"><link href="/js/lang-zh-CN-result-success.349556c5.js" rel="prefetch"><link href="/js/lang-zh-CN-result.5e7f6923.js" rel="prefetch"><link href="/js/lang-zh-CN-setting.78d9e9d1.js" rel="prefetch"><link href="/js/lang-zh-CN-user.696e6d3c.js" rel="prefetch"><link href="/js/lang-zh-CN.4df4bdd0.js" rel="prefetch"><link href="/js/user.2123b527.js" rel="prefetch"><link href="/css/app.7dac075b.css" rel="preload" as="style"><link href="/css/chunk-vendors.f716a607.css" rel="preload" as="style"><link href="/js/app.3d45d60a.js" rel="preload" as="script"><link href="/js/chunk-vendors.a56c9037.js" rel="preload" as="script"><link href="/css/chunk-vendors.f716a607.css" rel="stylesheet"><link href="/css/app.7dac075b.css" rel="stylesheet"></head><body><noscript><strong>We're sorry but vue-antd-pro doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"><div class="first-loading-wrp"><h1>X-RETRY</h1><div class="loading-wrp"><span class="dot dot-spin"><i></i><i></i><i></i><i></i></span></div><div style="display: flex; justify-content: center; align-items: center;">X-RETRY</div></div></div><script src="//cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.min.js"></script><script src="//cdn.jsdelivr.net/npm/vue-router@3.5.1/dist/vue-router.min.js"></script><script src="//cdn.jsdelivr.net/npm/vuex@3.1.1/dist/vuex.min.js"></script><script src="//cdn.jsdelivr.net/npm/axios@0.21.1/dist/axios.min.js"></script><script src="/js/chunk-vendors.a56c9037.js"></script><script src="/js/app.3d45d60a.js"></script></body></html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["lang-zh-CN-user"],{2518:function(e,r,s){"use strict";s.r(r),r["default"]={"user.login.userName":"用户名","user.login.password":"密码","user.login.username.placeholder":"请输入账号","user.login.password.placeholder":"请输入密码","user.login.message-invalid-credentials":"账户或密码错误","user.login.message-invalid-verification-code":"验证码错误","user.login.tab-login-credentials":"账户密码登录","user.login.tab-login-mobile":"手机号登录","user.login.mobile.placeholder":"手机号","user.login.mobile.verification-code.placeholder":"验证码","user.login.remember-me":"自动登录","user.login.forgot-password":"忘记密码","user.login.sign-in-with":"其他登录方式","user.login.signup":"注册账户","user.login.login":"登录","user.register.register":"注册","user.register.email.placeholder":"邮箱","user.register.password.placeholder":"请至少输入 6 个字符。请不要使用容易被猜到的密码。","user.register.password.popover-message":"请至少输入 6 个字符。请不要使用容易被猜到的密码。","user.register.confirm-password.placeholder":"确认密码","user.register.get-verification-code":"获取验证码","user.register.sign-in":"使用已有账户登录","user.register-result.msg":"你的账户:{email} 注册成功","user.register-result.activation-email":"激活邮件已发送到你的邮箱中邮件有效期为24小时。请及时登录邮箱点击邮件中的链接激活帐户。","user.register-result.back-home":"返回首页","user.register-result.view-mailbox":"查看邮箱","user.email.required":"请输入邮箱地址!","user.email.wrong-format":"邮箱地址格式错误!","user.userName.required":"请输入帐户名或邮箱地址","user.password.required":"请输入密码!","user.password.twice.msg":"两次输入的密码不匹配!","user.password.strength.msg":"密码强度不够 ","user.password.strength.strong":"强度:强","user.password.strength.medium":"强度:中","user.password.strength.low":"强度:低","user.password.strength.short":"强度:太短","user.confirm-password.required":"请确认密码!","user.phone-number.required":"请输入正确的手机号","user.phone-number.wrong-format":"手机号格式错误!","user.verification-code.required":"请输入验证码!"}}}]);

View File

@ -1 +0,0 @@
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["lang-zh-CN-user"],{2518:function(e,r,s){"use strict";s.r(r),r["default"]={"user.login.userName":"用户名","user.login.password":"密码","user.login.username.placeholder":"账户: admin","user.login.password.placeholder":"密码: admin or ant.design","user.login.message-invalid-credentials":"账户或密码错误","user.login.message-invalid-verification-code":"验证码错误","user.login.tab-login-credentials":"账户密码登录","user.login.tab-login-mobile":"手机号登录","user.login.mobile.placeholder":"手机号","user.login.mobile.verification-code.placeholder":"验证码","user.login.remember-me":"自动登录","user.login.forgot-password":"忘记密码","user.login.sign-in-with":"其他登录方式","user.login.signup":"注册账户","user.login.login":"登录","user.register.register":"注册","user.register.email.placeholder":"邮箱","user.register.password.placeholder":"请至少输入 6 个字符。请不要使用容易被猜到的密码。","user.register.password.popover-message":"请至少输入 6 个字符。请不要使用容易被猜到的密码。","user.register.confirm-password.placeholder":"确认密码","user.register.get-verification-code":"获取验证码","user.register.sign-in":"使用已有账户登录","user.register-result.msg":"你的账户:{email} 注册成功","user.register-result.activation-email":"激活邮件已发送到你的邮箱中邮件有效期为24小时。请及时登录邮箱点击邮件中的链接激活帐户。","user.register-result.back-home":"返回首页","user.register-result.view-mailbox":"查看邮箱","user.email.required":"请输入邮箱地址!","user.email.wrong-format":"邮箱地址格式错误!","user.userName.required":"请输入帐户名或邮箱地址","user.password.required":"请输入密码!","user.password.twice.msg":"两次输入的密码不匹配!","user.password.strength.msg":"密码强度不够 ","user.password.strength.strong":"强度:强","user.password.strength.medium":"强度:中","user.password.strength.low":"强度:低","user.password.strength.short":"强度:太短","user.confirm-password.required":"请确认密码!","user.phone-number.required":"请输入正确的手机号","user.phone-number.wrong-format":"手机号格式错误!","user.verification-code.required":"请输入验证码!"}}}]);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,6 +1,4 @@
spring:
profiles:
active: dev
datasource:
name: x_retry
url: jdbc:mysql://localhost:3306/x_retry?useSSL=false&characterEncoding=utf8&useUnicode=true
@ -32,6 +30,10 @@ mybatis-plus:
map-underscore-to-camel-case: true
cache-enabled: true
x-retry:
lastDays: 30 # 拉取重试数据的天数
retryPullPageSize: 100 # 拉取重试数据的每批次的大小
nettyPort: 1788 # 服务端netty端口
totalPartition: 32 # 重试和死信表的分区总数