Merge remote-tracking branch 'origin/dev_3.2.0' into dev_3.2.0

This commit is contained in:
zhengweilin 2024-03-25 09:58:23 +08:00
commit bb69b0cf9a
44 changed files with 4021 additions and 28 deletions

View File

@ -6,6 +6,7 @@ volumes:
mysql: { }
postgres: { }
oracle: { }
sqlserver: { }
services:
mysql:
@ -54,3 +55,17 @@ services:
# 创建app用户: root/root@//localhost/XEPDB1
- ./oracle/1_create_user.sql:/docker-entrypoint-initdb.d/1_create_user.sql:ro
- ./oracle/2_create_schema.sh:/docker-entrypoint-initdb.d/2_create_schema.sh:ro
sqlserver:
image: mcr.microsoft.com/mssql/server:2017-latest
environment:
TZ: Asia/Shanghai
ACCEPT_EULA: "Y"
SA_PASSWORD: "EasyRetry@24"
ports:
- "1433:1433"
volumes:
- sqlserver:/var/opt/mssql
- ../sql/easy_retry_sqlserver.sql:/tmp/schema.sql:ro
# docker compose exec sqlserver bash /tmp/create_schema.sh
- ./sqlserver/create_schema.sh:/tmp/create_schema.sh:ro

View File

@ -0,0 +1,5 @@
#!/usr/bin/env bash
/opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P 'EasyRetry@24' -Q "CREATE DATABASE easy_retry;
GO"
/opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P 'EasyRetry@24' -d easy_retry -i /tmp/schema.sql

File diff suppressed because it is too large Load Diff

View File

@ -37,10 +37,12 @@ public abstract class AbstractConfigAccess<T> implements ConfigAccess<T> {
@Autowired
protected Environment environment;
protected static final List<String> ALLOW_DB = Arrays.asList(DbTypeEnum.MYSQL.getDb(),
protected static final List<String> ALLOW_DB = Arrays.asList(
DbTypeEnum.MYSQL.getDb(),
DbTypeEnum.MARIADB.getDb(),
DbTypeEnum.POSTGRES.getDb(),
DbTypeEnum.ORACLE.getDb());
DbTypeEnum.ORACLE.getDb(),
DbTypeEnum.SQLSERVER.getDb());
protected DbTypeEnum getDbType() {
String dbType = environment.getProperty("easy-retry.db-type");

View File

@ -21,10 +21,12 @@ public abstract class AbstractTaskAccess<T> implements TaskAccess<T> {
@Autowired
protected Environment environment;
protected static final List<String> ALLOW_DB = Arrays.asList(DbTypeEnum.MYSQL.getDb(),
protected static final List<String> ALLOW_DB = Arrays.asList(
DbTypeEnum.MYSQL.getDb(),
DbTypeEnum.MARIADB.getDb(),
DbTypeEnum.POSTGRES.getDb(),
DbTypeEnum.ORACLE.getDb());
DbTypeEnum.ORACLE.getDb(),
DbTypeEnum.SQLSERVER.getDb());
protected DbTypeEnum getDbType() {
String dbType = environment.getProperty("easy-retry.db-type");

View File

@ -20,7 +20,8 @@ public enum DbTypeEnum {
MYSQL("mysql", "MySql数据库", DbType.MYSQL),
MARIADB("mariadb", "MariaDB数据库", DbType.MARIADB),
POSTGRES("postgres", "Postgres数据库", DbType.POSTGRE_SQL),
ORACLE("oracle", "Oracle数据库", DbType.ORACLE_12C);
ORACLE("oracle", "Oracle数据库", DbType.ORACLE_12C),
SQLSERVER("sqlserver", "SQLServer数据库", DbType.SQL_SERVER);
private final String db;
private final String desc;

View File

@ -14,7 +14,7 @@ import java.time.LocalDateTime;
* @author www.byteblogs.com
* @since 2022-03-05
*/
@TableName("system_user")
@TableName("system_user") // NOTE: system_user表是SQL Server系统函数, 这里需要修改为 system_user_, [system_user]不支持子查询
@Data
public class SystemUser implements Serializable {
@ -33,9 +33,4 @@ public class SystemUser implements Serializable {
private LocalDateTime updateDt;
public Long getId() {
return id;
}
}

View File

@ -0,0 +1,35 @@
HELP.md
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/
### 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/
!**/src/main/**/build/
!**/src/test/**/build/
### VS Code ###
.vscode/
.flattened-pom.xml

View File

@ -0,0 +1,59 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.aizuda</groupId>
<artifactId>easy-retry-datasource</artifactId>
<version>${revision}</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>easy-retry-sqlserver-datasource</artifactId>
<name>easy-retry-sqlserver-datasource</name>
<description>easy-retry-sqlserver-datasource</description>
<packaging>jar</packaging>
<properties>
<java.version>17</java.version>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
</dependency>
<dependency>
<groupId>com.aizuda</groupId>
<artifactId>easy-retry-datasource-template</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>none</mainClass> <!-- 取消查找本项目下的Main方法为了解决Unable to find main class的问题 -->
<classifier>execute</classifier> <!-- 为了解决依赖模块找不到此模块中的类或属性 -->
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,16 @@
package com.aizuda.easy.retry.sqlserver.datasource.config;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
/**
* @author: www.byteblogs.com
* @date : 2024-03-19 22:05
*/
@Configuration
@ComponentScan("com.aizuda.easy.retry.sqlserver.datasource.*")
@ConditionalOnProperty(prefix = "easy-retry", name = "db-type", havingValue = "sqlserver")
public class EasyRetrySqlServerAutoConfiguration {
}

View File

@ -0,0 +1 @@
com.aizuda.easy.retry.sqlserver.datasource.config.EasyRetrySqlServerAutoConfiguration

View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.aizuda.easy.retry.template.datasource.persistence.mapper.DistributedLockMapper">
<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="com.aizuda.easy.retry.template.datasource.persistence.po.DistributedLock">
<id column="id" property="id" />
<result column="name" property="name" />
<result column="lock_until" property="lockUntil" />
<result column="locked_at" property="lockedAt" />
<result column="locked_by" property="lockedBy" />
<result column="create_dt" property="createDt" />
<result column="update_dt" property="updateDt" />
</resultMap>
<!-- 通用查询结果列 -->
<sql id="Base_Column_List">
id, name, lock_until, locked_at, locked_by, create_dt, update_dt
</sql>
<update id="updateTest">
UPDATE distributed_lock SET locked_by = #{lockedBy},
lock_until = #{lockUntil},
locked_at = #{lockedAt}
WHERE name = #{name} AND lock_until <![CDATA[ <= ]]> #{lockedAt}
</update>
</mapper>

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.aizuda.easy.retry.template.datasource.persistence.mapper.GroupConfigMapper">
<resultMap id="BaseResultMap" type="com.aizuda.easy.retry.template.datasource.persistence.po.GroupConfig">
<id column="id" jdbcType="BIGINT" property="id" />
<result column="group_name" jdbcType="VARCHAR" property="groupName" />
<result column="group_status" jdbcType="TINYINT" property="groupStatus" />
<result column="version" jdbcType="TINYINT" property="version" />
<result column="group_partition" jdbcType="TINYINT" property="groupPartition" />
<result column="route_key" jdbcType="TINYINT" property="routeKey" />
<result column="id_generator_mode" jdbcType="TINYINT" property="idGeneratorMode" />
<result column="init_scene" jdbcType="TINYINT" property="initScene" />
<result column="description" jdbcType="TINYINT" property="description" />
<result column="create_dt" jdbcType="TIMESTAMP" property="createDt" />
<result column="update_dt" jdbcType="TIMESTAMP" property="updateDt" />
</resultMap>
<sql id="Base_Column_List">
id, `group_name`, group_status, version, `group_partition`, route_key, id_generator_mode, init_scene description, create_dt, update_dt
</sql>
</mapper>

View File

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.aizuda.easy.retry.template.datasource.persistence.mapper.JobLogMessageMapper">
<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="com.aizuda.easy.retry.template.datasource.persistence.po.JobLogMessage">
<id column="id" property="id"/>
<result column="namespace_id" property="namespaceId"/>
<result column="group_name" property="groupName"/>
<result column="job_id" property="jobId"/>
<result column="task_batch_id" property="taskBatchId"/>
<result column="task_id" property="taskId"/>
<result column="log_num" property="logNum"/>
<result column="message" property="message"/>
<result column="create_dt" property="createDt"/>
<result column="real_time" property="realTime"/>
</resultMap>
<!-- 定义批量新增的 SQL 映射 -->
<insert id="batchInsert" parameterType="java.util.List">
INSERT INTO job_log_message (namespace_id, group_name, job_id, task_batch_id, task_id,
log_num, message, create_dt, real_time)
VALUES
<foreach collection="list" item="item" separator=",">
(
#{item.namespaceId},
#{item.groupName},
#{item.jobId},
#{item.taskBatchId},
#{item.taskId},
#{item.logNum},
#{item.message},
#{item.createDt},
#{item.realTime}
)
</foreach>
</insert>
</mapper>

View File

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.aizuda.easy.retry.template.datasource.persistence.mapper.JobMapper">
<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="com.aizuda.easy.retry.template.datasource.persistence.po.Job">
<id column="id" property="id"/>
<result column="group_name" property="groupName"/>
<result column="job_name" property="jobName"/>
<result column="args_str" property="argsStr"/>
<result column="args_type" property="argsType"/>
<result column="ext_attrs" property="extAttrs"/>
<result column="next_trigger_at" property="nextTriggerAt"/>
<result column="job_status" property="jobStatus"/>
<result column="route_key" property="routeKey"/>
<result column="executor_type" property="executorType"/>
<result column="executor_info" property="executorInfo"/>
<result column="block_strategy" property="blockStrategy"/>
<result column="executor_timeout" property="executorTimeout"/>
<result column="max_retry_times" property="maxRetryTimes"/>
<result column="retry_interval" property="retryInterval"/>
<result column="bucket_index" property="bucketIndex"/>
<result column="description" property="description"/>
<result column="create_dt" property="createDt"/>
<result column="update_dt" property="updateDt"/>
<result column="deleted" property="deleted"/>
</resultMap>
<update id="updateBatchNextTriggerAtById" parameterType="java.util.List">
UPDATE job
SET job.next_trigger_at = src.next_trigger_at
FROM job
JOIN (
<foreach collection="list" item="item" index="index" separator=" UNION ALL ">
SELECT
#{item.nextTriggerAt} AS next_trigger_at,
#{item.id} AS id
</foreach>
) AS src ON job.id = src.id;
</update>
</mapper>

View File

@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.aizuda.easy.retry.template.datasource.persistence.mapper.JobNotifyConfigMapper">
<resultMap id="BaseResultMap" type="com.aizuda.easy.retry.template.datasource.persistence.po.JobNotifyConfig">
<id column="id" jdbcType="BIGINT" property="id" />
<result column="namespace_id" jdbcType="VARCHAR" property="namespaceId" />
<result column="group_name" jdbcType="VARCHAR" property="groupName" />
<result column="job_id" jdbcType="BIGINT" property="jobId" />
<result column="notify_status" jdbcType="TINYINT" property="notifyStatus" />
<result column="notify_type" jdbcType="TINYINT" property="notifyType" />
<result column="notify_attribute" jdbcType="VARCHAR" property="notifyAttribute" />
<result column="notify_threshold" jdbcType="TINYINT" property="notifyThreshold" />
<result column="notify_scene" jdbcType="TINYINT" property="notifyScene" />
<result column="rate_limiter_status" jdbcType="TINYINT" property="rateLimiterStatus" />
<result column="rate_limiter_threshold" jdbcType="TINYINT" property="rateLimiterThreshold" />
<result column="description" jdbcType="VARCHAR" property="description" />
<result column="create_dt" jdbcType="TIMESTAMP" property="createDt" />
<result column="update_dt" jdbcType="TIMESTAMP" property="updateDt" />
</resultMap>
<sql id="Base_Column_List">
id,namespace_id, group_name,job_id,notify_status,notify_type, notify_attribute, notify_threshold, notify_scene,rate_limiter_status,rate_limiter_threshold, description,
create_dt, update_dt
</sql>
<select id="selectJobNotifyConfigList"
resultType="com.aizuda.easy.retry.template.datasource.persistence.dataobject.JobNotifyConfigResponseDO">
SELECT a.*,
b.job_name
FROM job_notify_config a
JOIN job b ON a.job_id = b.id
<where>
a.namespace_id = #{queryDO.namespaceId}
<if test="queryDO.jobId != null">
AND a.job_id = #{queryDO.jobId}
</if>
<if test="queryDO.groupNames != null and queryDO.groupNames.size > 0">
AND a.group_name IN
<foreach collection="queryDO.groupNames" item="groupName" open="(" separator="," close=")">
#{groupName}
</foreach>
</if>
</where>
ORDER BY a.id DESC
</select>
</mapper>

View File

@ -0,0 +1,186 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.aizuda.easy.retry.template.datasource.persistence.mapper.JobSummaryMapper">
<resultMap id="BaseResultMap" type="com.aizuda.easy.retry.template.datasource.persistence.po.JobSummary">
<id column="id" jdbcType="BIGINT" property="id"/>
<result column="namespace_id" jdbcType="TINYINT" property="namespaceId"/>
<result column="group_name" jdbcType="TINYINT" property="groupName"/>
<result column="job_id" jdbcType="TINYINT" property="jobId"/>
<result column="trigger_at" jdbcType="TIMESTAMP" property="triggerAt"/>
<result column="success_num" jdbcType="TINYINT" property="successNum"/>
<result column="fail_num" jdbcType="TINYINT" property="failNum"/>
<result column="fail_reason" jdbcType="VARCHAR" property="failReason"/>
<result column="stop_num" jdbcType="TINYINT" property="stopNum"/>
<result column="stop_reason" jdbcType="VARCHAR" property="stopReason"/>
<result column="cancel_num" jdbcType="TINYINT" property="cancelNum"/>
<result column="cancel_reason" jdbcType="VARCHAR" property="cancelReason"/>
<result column="create_dt" jdbcType="TIMESTAMP" property="createDt"/>
<result column="update_dt" jdbcType="TIMESTAMP" property="updateDt"/>
</resultMap>
<insert id="insertOrUpdate" parameterType="java.util.List" useGeneratedKeys="true" keyProperty="id">
MERGE INTO job_summary AS target
USING (
VALUES
<foreach collection="list" item="item" separator=",">
(
#{item.namespaceId},
#{item.groupName},
#{item.jobId},
#{item.triggerAt},
#{item.successNum},
#{item.failNum},
#{item.failReason},
#{item.stopNum},
#{item.stopReason},
#{item.cancelNum},
#{item.cancelReason}
)
</foreach>
) AS source (namespace_id, group_name, job_id, trigger_at,
success_num, fail_num, fail_reason, stop_num, stop_reason, cancel_num, cancel_reason)
ON target.namespace_id = source.namespace_id
AND target.job_id = source.job_id
WHEN MATCHED THEN
UPDATE SET
target.success_num = source.success_num,
target.fail_num = source.fail_num,
target.fail_reason = source.fail_reason,
target.stop_num = source.stop_num,
target.stop_reason = source.stop_reason,
target.cancel_num = source.cancel_num,
target.cancel_reason = source.cancel_reason
WHEN NOT MATCHED THEN
INSERT (namespace_id, group_name, job_id, trigger_at,
success_num, fail_num, fail_reason, stop_num, stop_reason, cancel_num, cancel_reason)
VALUES (source.namespace_id, source.group_name, source.job_id, source.trigger_at,
source.success_num, source.fail_num, source.fail_reason, source.stop_num, source.stop_reason,
source.cancel_num, source.cancel_reason);
</insert>
<select id="jobLineList"
resultType="com.aizuda.easy.retry.template.datasource.persistence.dataobject.DashboardLineResponseDO">
SELECT
createDt,
ISNULL(SUM(success_num), 0) AS success,
ISNULL(SUM(stop_num), 0) AS stop,
ISNULL(SUM(cancel_num), 0) AS cancel,
ISNULL(SUM(fail_num), 0) AS fail,
ISNULL(SUM(success_num + fail_num + stop_num + cancel_num), 0) AS total
FROM (
SELECT
<choose>
<when test="type == 'DAY'">
FORMAT(create_dt,'HH24')
</when>
<when test="type == 'WEEK'">
FORMAT(create_dt,'yyyy-MM-dd')
</when>
<when test="type =='MONTH'">
FORMAT(create_dt,'yyyy-MM-dd')
</when>
<when test="type == 'YEAR'">
FORMAT(create_dt,'yyyy-MM')
</when>
<otherwise>
FORMAT(create_dt,'yyyy-MM-dd')
</otherwise>
</choose> AS createDt,
success_num,
stop_num,
cancel_num,
fail_num
FROM job_summary
<where>
<if test="groupNames != null and groupNames.size > 0">
AND group_name IN
<foreach collection="groupNames" item="groupName" open="(" separator="," close=")">
#{groupName}
</foreach>
</if>
<if test="groupName != null and groupName != '' ">
AND group_name = #{groupName}
</if>
AND namespace_id = #{namespaceId}
AND trigger_at BETWEEN #{from} AND #{to}
</where>
) AS subquery
GROUP BY createDt
</select>
<select id="toJobTask"
resultType="com.aizuda.easy.retry.template.datasource.persistence.dataobject.DashboardCardResponseDO$JobTask">
SELECT
ISNULL(sum(success_num), 0) AS successNum,
ISNULL(sum(stop_num), 0) AS stopNum,
ISNULL(sum(cancel_num), 0) AS cancelNum,
ISNULL(sum(fail_num), 0) AS failNum,
ISNULL(sum(success_num + fail_num + stop_num + cancel_num), 0) AS totalNum
FROM job_summary
WHERE namespace_id = #{namespaceId}
<if test="groupNames != null and groupNames.size > 0">
AND group_name IN
<foreach collection="groupNames" item="groupName" open="(" separator="," close=")">
#{groupName}
</foreach>
</if>
</select>
<select id="dashboardRank"
resultType="com.aizuda.easy.retry.template.datasource.persistence.dataobject.DashboardRetryLineResponseDO$Rank">
SELECT TOP 10
CONCAT(group_name, '/', (SELECT job_name FROM job WHERE id=job_id)) name,
SUM(fail_num) AS total
FROM job_summary
<where>
<if test="groupNames != null and groupNames.size > 0">
AND group_name IN
<foreach collection="groupNames" item="groupName" open="(" separator="," close=")">
#{groupName}
</foreach>
</if>
<if test="groupName != '' and groupName != null">
AND group_name = #{groupName}
</if>
AND trigger_at BETWEEN #{startTime} AND #{endTime}
AND namespace_id = #{namespaceId}
</where>
GROUP BY namespace_id, group_name, job_id
HAVING SUM(fail_num) > 0
ORDER BY name DESC
</select>
<!-- SQL Server GROUP BY 的分页必须 ORDER BY xxx -->
<select id="jobTaskList"
resultType="com.aizuda.easy.retry.template.datasource.persistence.dataobject.DashboardRetryLineResponseDO$Task">
SELECT
group_name AS groupName,
SUM(CASE WHEN (job_status = 1) THEN 1 ELSE 0 END) AS run,
COUNT(*) AS total
FROM job
WHERE namespace_id = #{namespaceId}
<if test="groupNames != null and groupNames.size > 0">
AND group_name IN
<foreach collection="groupNames" item="groupName" open="(" separator="," close=")">
#{groupName}
</foreach>
</if>
GROUP BY namespace_id, group_name
ORDER BY group_name
</select>
<!-- 用于 jobTaskList 分页的 COUNT,
SQL Server SELECT COUNT(*) FROM (... ORDER BY ) 会报错 -->
<select id="sqlServer_jobTaskList_Count"
resultType="com.aizuda.easy.retry.template.datasource.persistence.dataobject.DashboardRetryLineResponseDO$Task">
SELECT COUNT(DISTINCT group_name)
FROM job
WHERE namespace_id = #{namespaceId}
<if test="groupNames != null and groupNames.size > 0">
AND group_name IN
<foreach collection="groupNames" item="groupName" open="(" separator="," close=")">
#{groupName}
</foreach>
</if>
</select>
</mapper>

View File

@ -0,0 +1,89 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.aizuda.easy.retry.template.datasource.persistence.mapper.JobTaskBatchMapper">
<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="com.aizuda.easy.retry.template.datasource.persistence.po.JobTaskBatch">
<id column="id" property="id" />
<result column="group_name" property="groupName" />
<result column="job_id" property="jobId" />
<result column="namespace_id" property="namespaceId" />
<result column="task_batch_status" property="taskBatchStatus" />
<result column="create_dt" property="createDt" />
<result column="update_dt" property="updateDt" />
<result column="deleted" property="deleted" />
</resultMap>
<select id="selectJobBatchPageList"
parameterType="com.aizuda.easy.retry.template.datasource.persistence.dataobject.JobBatchQueryDO"
resultType="com.aizuda.easy.retry.template.datasource.persistence.dataobject.JobBatchResponseDO">
SELECT
a.*,
b.job_name,
b.task_type,
b.block_strategy,
b.trigger_type
FROM job_task_batch a
JOIN job b ON a.job_id = b.id
<where>
a.namespace_id = #{queryDO.namespaceId}
AND a.system_task_type = 3
<if test="queryDO.jobId != null">
AND a.job_id = #{queryDO.jobId}
</if>
<if test="queryDO.groupNames != null and queryDO.groupNames.size > 0">
AND a.group_name IN
<foreach collection="queryDO.groupNames" item="groupName" open="(" separator="," close=")">
#{groupName}
</foreach>
</if>
<if test="queryDO.taskBatchStatus != null">
AND task_batch_status = #{queryDO.taskBatchStatus}
</if>
<if test="queryDO.jobName != null">
AND job_name like #{queryDO.jobName}
</if>
AND a.deleted = 0
</where>
ORDER BY a.id DESC
</select>
<select id="summaryJobBatchList"
resultType="com.aizuda.easy.retry.template.datasource.persistence.dataobject.JobBatchSummaryResponseDO">
SELECT namespace_id AS namespaceId,
job_id AS jobId,
group_name AS groupName,
task_batch_status AS taskBatchStatus,
operation_reason AS operationReason,
COUNT(operation_reason) AS operationReasonTotal,
SUM(CASE WHEN (task_batch_status = 3) THEN 1 ELSE 0 END) AS successNum,
SUM(CASE WHEN (task_batch_status = 6) THEN 1 ELSE 0 END) AS cancelNum,
SUM(CASE WHEN (task_batch_status = 5) THEN 1 ELSE 0 END) AS stopNum,
SUM(CASE WHEN (task_batch_status = 4) THEN 1 ELSE 0 END) AS failNum
FROM job_task_batch
WHERE create_dt BETWEEN #{from} AND #{to}
GROUP BY namespace_id, group_name, job_id, task_batch_status, operation_reason
</select>
<select id="selectJobBatchListByIds"
resultType="com.aizuda.easy.retry.template.datasource.persistence.dataobject.JobBatchResponseDO">
SELECT
a.*,
b.job_name,
b.task_type,
b.block_strategy,
b.trigger_type,
b.executor_info,
b.args_str
FROM
job_task_batch a
JOIN job b ON a.job_id = b.id
<where>
a.id IN
<foreach collection="ids" item="id" separator="," open="(" close=")">
#{id}
</foreach>
AND a.deleted = 0
</where>
</select>
</mapper>

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.aizuda.easy.retry.template.datasource.persistence.mapper.JobTaskMapper">
<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="com.aizuda.easy.retry.template.datasource.persistence.po.JobTask">
<id column="id" property="id" />
<result column="group_name" property="groupName" />
<result column="job_id" property="jobId" />
<result column="task_batch_id" property="taskBatchId" />
<result column="parent_id" property="parentId" />
<result column="execute_status" property="executeStatus" />
<result column="result_message" property="resultMessage" />
<result column="create_dt" property="createDt" />
<result column="update_dt" property="updateDt" />
</resultMap>
</mapper>

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.aizuda.easy.retry.template.datasource.persistence.mapper.NamespaceMapper">
<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="com.aizuda.easy.retry.template.datasource.persistence.po.Namespace">
<id column="id" property="id" />
<result column="name" property="name" />
<result column="unique_id" property="uniqueId" />
<result column="create_dt" property="createDt" />
<result column="update_dt" property="updateDt" />
<result column="deleted" property="deleted" />
</resultMap>
</mapper>

View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.aizuda.easy.retry.template.datasource.persistence.mapper.NotifyConfigMapper">
<resultMap id="BaseResultMap" type="com.aizuda.easy.retry.template.datasource.persistence.po.NotifyConfig">
<id column="id" jdbcType="BIGINT" property="id" />
<result column="group_name" jdbcType="VARCHAR" property="groupName" />
<result column="notify_type" jdbcType="TINYINT" property="notifyType" />
<result column="notify_attribute" jdbcType="VARCHAR" property="notifyAttribute" />
<result column="notify_threshold" jdbcType="TINYINT" property="notifyThreshold" />
<result column="notify_scene" jdbcType="TINYINT" property="notifyScene" />
<result column="description" jdbcType="VARCHAR" property="description" />
<result column="create_dt" jdbcType="TIMESTAMP" property="createDt" />
<result column="update_dt" jdbcType="TIMESTAMP" property="updateDt" />
</resultMap>
<sql id="Base_Column_List">
id, group_name, notify_type, notify_attribute, notify_threshold, notify_scene, description,
create_dt, update_dt
</sql>
</mapper>

View File

@ -0,0 +1,44 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.aizuda.easy.retry.template.datasource.persistence.mapper.RetryDeadLetterMapper">
<resultMap id="BaseResultMap" type="com.aizuda.easy.retry.template.datasource.persistence.po.RetryDeadLetter">
<id column="id" jdbcType="BIGINT" property="id" />
<result column="namespace_id" jdbcType="VARCHAR" property="namespaceId"/>
<result column="unique_id" jdbcType="VARCHAR" property="uniqueId"/>
<result column="group_name" jdbcType="VARCHAR" property="groupName" />
<result column="scene_name" jdbcType="VARCHAR" property="sceneName" />
<result column="idempotent_id" jdbcType="VARCHAR" property="idempotentId" />
<result column="biz_no" jdbcType="VARCHAR" property="bizNo" />
<result column="executor_name" jdbcType="VARCHAR" property="executorName" />
<result column="args_str" jdbcType="VARCHAR" property="argsStr" />
<result column="ext_attrs" jdbcType="VARCHAR" property="extAttrs" />
<result column="task_type" jdbcType="TINYINT" property="taskType"/>
<result column="create_dt" jdbcType="TIMESTAMP" property="createDt" />
</resultMap>
<sql id="Base_Column_List">
id, unique_id, group_name, scene_name, idempotent_id, biz_no, executor_name, args_str, ext_attrs, create_dt, task_type
</sql>
<insert id="insertBatch">
INSERT INTO retry_dead_letter (namespace_id, unique_id, group_name, scene_name,
idempotent_id, biz_no, executor_name, args_str,
ext_attrs, create_dt)
values
<foreach collection="retryDeadLetters" item="retryDeadLetter" separator=",">
(
#{retryDeadLetter.namespaceId,jdbcType=VARCHAR},
#{retryDeadLetter.uniqueId,jdbcType=VARCHAR},
#{retryDeadLetter.groupName,jdbcType=VARCHAR},
#{retryDeadLetter.sceneName,jdbcType=VARCHAR},
#{retryDeadLetter.idempotentId,jdbcType=VARCHAR},
#{retryDeadLetter.bizNo,jdbcType=VARCHAR},
#{retryDeadLetter.executorName,jdbcType=VARCHAR},
#{retryDeadLetter.argsStr,jdbcType=VARCHAR},
#{retryDeadLetter.extAttrs,jdbcType=VARCHAR},
#{retryDeadLetter.createDt,jdbcType=TIMESTAMP}
)
</foreach>
</insert>
</mapper>

View File

@ -0,0 +1,198 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.aizuda.easy.retry.template.datasource.persistence.mapper.RetrySummaryMapper">
<resultMap id="BaseResultMap" type="com.aizuda.easy.retry.template.datasource.persistence.po.RetrySummary">
<id column="id" jdbcType="BIGINT" property="id"/>
<result column="namespace_id" jdbcType="TINYINT" property="namespaceId"/>
<result column="group_name" jdbcType="TINYINT" property="groupName"/>
<result column="scene_name" jdbcType="TINYINT" property="sceneName"/>
<result column="trigger_at" jdbcType="TIMESTAMP" property="triggerAt"/>
<result column="running_num" jdbcType="TINYINT" property="runningNum"/>
<result column="finish_num" jdbcType="TINYINT" property="finishNum"/>
<result column="max_count_num" jdbcType="VARCHAR" property="maxCountNum"/>
<result column="suspend_num" jdbcType="TINYINT" property="suspendNum"/>
<result column="create_dt" jdbcType="TIMESTAMP" property="createDt"/>
<result column="update_dt" jdbcType="TIMESTAMP" property="updateDt"/>
</resultMap>
<insert id="insertOrUpdate" parameterType="java.util.List" useGeneratedKeys="true" keyProperty="id">
MERGE INTO retry_summary AS target
USING (
VALUES
<foreach collection="list" item="item" separator=",">
(
#{item.namespaceId},
#{item.groupName},
#{item.sceneName},
#{item.triggerAt},
#{item.runningNum},
#{item.finishNum},
#{item.maxCountNum},
#{item.suspendNum}
)
</foreach>
) AS source (namespace_id, group_name, scene_name, trigger_at,
running_num, finish_num, max_count_num, suspend_num)
ON target.namespace_id = source.namespace_id
AND target.group_name = source.group_name
AND target.scene_name = source.scene_name
AND target.trigger_at = source.trigger_at
WHEN MATCHED THEN
UPDATE SET
target.running_num = source.running_num,
target.finish_num = source.finish_num,
target.max_count_num = source.max_count_num,
target.suspend_num = source.suspend_num
WHEN NOT MATCHED THEN
INSERT (namespace_id, group_name, scene_name, trigger_at,
running_num, finish_num, max_count_num, suspend_num)
VALUES (source.namespace_id, source.group_name, source.scene_name, source.trigger_at,
source.running_num, source.finish_num, source.max_count_num, source.suspend_num);
</insert>
<select id="retryTask"
resultType="com.aizuda.easy.retry.template.datasource.persistence.dataobject.DashboardCardResponseDO$RetryTask">
SELECT
ISNULL(SUM(running_num), 0) AS runningNum,
ISNULL(SUM(finish_num), 0) AS finishNum,
ISNULL(SUM(max_count_num), 0) AS maxCountNum,
ISNULL(SUM(suspend_num), 0) AS suspendNum,
ISNULL(SUM(running_num + finish_num + max_count_num + suspend_num), 0) AS totalNum
FROM retry_summary
WHERE namespace_id = #{namespaceId}
<if test="groupNames != null and groupNames.size > 0">
AND group_name IN
<foreach collection="groupNames" item="groupName" open="(" separator="," close=")">
#{groupName}
</foreach>
</if>
</select>
<select id="retryTaskBarList"
resultType="com.aizuda.easy.retry.template.datasource.persistence.dataobject.DashboardCardResponseDO$RetryTask">
SELECT TOP 7
trigger_at,
running_num,
finish_num,
max_count_num,
suspend_num
FROM retry_summary
WHERE
namespace_id = #{namespaceId}
<if test="groupNames != null and groupNames.size > 0">
AND group_name IN
<foreach collection="groupNames" item="groupName" open="(" separator="," close=")">
#{groupName}
</foreach>
</if>
ORDER BY id DESC
</select>
<select id="retryLineList"
resultType="com.aizuda.easy.retry.template.datasource.persistence.dataobject.DashboardLineResponseDO">
SELECT
createDt,
ISNULL(SUM(finish_num), 0) AS successNum,
ISNULL(SUM(running_num), 0) AS runningNum,
ISNULL(SUM(max_count_num), 0) AS maxCountNum,
ISNULL(SUM(suspend_num), 0) AS suspendNum,
ISNULL(SUM(finish_num + running_num + max_count_num + suspend_num), 0) AS total
FROM (
SELECT
<choose>
<when test="type == 'DAY'">
FORMAT(create_dt, 'HH24')
</when>
<when test="type == 'WEEK'">
FORMAT(create_dt, 'yyyy-MM-dd')
</when>
<when test="type =='MONTH'">
FORMAT(create_dt, 'yyyy-MM-dd')
</when>
<when test="type == 'YEAR'">
FORMAT(create_dt, 'yyyy-MM')
</when>
<otherwise>
FORMAT(create_dt,'yyyy-MM-dd')
</otherwise>
</choose> AS createDt,
finish_num,
running_num,
max_count_num,
suspend_num
FROM retry_summary
<where>
<if test="groupNames != null and groupNames.size > 0">
AND group_name IN
<foreach collection="groupNames" item="groupName" open="(" separator="," close=")">
#{groupName}
</foreach>
</if>
<if test="groupName != null and groupName != '' ">
AND group_name = #{groupName}
</if>
AND namespace_id = #{namespaceId}
AND trigger_at BETWEEN #{from} AND #{to}
</where>
) AS subquery
GROUP BY createDt
</select>
<select id="dashboardRank"
resultType="com.aizuda.easy.retry.template.datasource.persistence.dataobject.DashboardRetryLineResponseDO$Rank">
SELECT TOP 10
CONCAT(group_name, '/', scene_name) AS name,
SUM(running_num + finish_num + max_count_num + suspend_num) AS total
FROM retry_summary
<where>
<if test="groupNames != null and groupNames.size > 0">
AND group_name IN
<foreach collection="groupNames" item="groupName" open="(" separator="," close=")">
#{groupName}
</foreach>
</if>
<if test="groupName != '' and groupName != null">
AND group_name = #{groupName}
</if>
AND namespace_id = #{namespaceId}
AND trigger_at BETWEEN #{startTime} AND #{endTime}
</where>
GROUP BY namespace_id, group_name, scene_name
HAVING SUM(running_num + finish_num + max_count_num + suspend_num) > 0
ORDER BY total DESC
</select>
<!-- SQL Server GROUP BY 的分页必须 ORDER BY xxx -->
<select id="retryTaskList"
resultType="com.aizuda.easy.retry.template.datasource.persistence.dataobject.DashboardRetryLineResponseDO$Task">
SELECT
group_name AS groupName,
SUM(CASE WHEN (scene_status = 1) THEN 1 ELSE 0 END) AS run,
COUNT(*) AS total
FROM scene_config
WHERE
namespace_id = #{namespaceId}
<if test="groupNames != null and groupNames.size > 0">
AND group_name IN
<foreach collection="groupNames" item="groupName" open="(" separator="," close=")">
#{groupName}
</foreach>
</if>
GROUP BY namespace_id, group_name
ORDER BY group_name
</select>
<!-- 用于 retryTaskList 分页的 自定义 COUNT,
SQL Server SELECT COUNT(*) FROM (... ORDER BY group_name) 会报错 -->
<select id="sqlServer_jobTaskList_Count" resultType="java.lang.Integer">
SELECT COUNT(DISTINCT group_name)
FROM scene_config
WHERE namespace_id = #{namespaceId}
<if test="groupNames != null and groupNames.size > 0">
AND group_name IN
<foreach collection="groupNames" item="groupName" open="(" separator="," close=")">
#{groupName}
</foreach>
</if>
</select>
</mapper>

View File

@ -0,0 +1,51 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.aizuda.easy.retry.template.datasource.persistence.mapper.RetryTaskLogMapper">
<resultMap id="BaseResultMap" type="com.aizuda.easy.retry.template.datasource.persistence.po.RetryTaskLog">
<id column="id" jdbcType="BIGINT" property="id"/>
<result column="unique_id" jdbcType="VARCHAR" property="uniqueId"/>
<result column="namespace_id" jdbcType="VARCHAR" property="namespaceId"/>
<result column="group_name" jdbcType="VARCHAR" property="groupName"/>
<result column="scene_name" jdbcType="VARCHAR" property="sceneName"/>
<result column="idempotent_id" jdbcType="VARCHAR" property="idempotentId"/>
<result column="biz_no" jdbcType="VARCHAR" property="bizNo"/>
<result column="executor_name" jdbcType="VARCHAR" property="executorName"/>
<result column="args_str" jdbcType="VARCHAR" property="argsStr"/>
<result column="ext_attrs" jdbcType="VARCHAR" property="extAttrs"/>
<result column="retry_status" jdbcType="TINYINT" property="retryStatus"/>
<result column="task_type" jdbcType="TINYINT" property="taskType"/>
<result column="create_dt" jdbcType="TIMESTAMP" property="createDt"/>
</resultMap>
<sql id="Base_Column_List">
id, unique_id, group_name, scene_name, idempotent_id, biz_no, executor_name, args_str, ext_attrs, retry_status,
create_dt, task_type, namespace_id
</sql>
<!-- 定义批量新增的 SQL 映射 -->
<insert id="batchInsert" parameterType="java.util.List">
INSERT INTO retry_task_log (unique_id, group_name, scene_name, idempotent_id, biz_no, executor_name,
args_str, ext_attrs, task_type, create_dt, namespace_id)
VALUES
<foreach collection="list" item="item" separator=",">
(#{item.uniqueId}, #{item.groupName}, #{item.sceneName}, #{item.idempotentId},
#{item.bizNo}, #{item.executorName}, #{item.argsStr}, #{item.extAttrs},
#{item.taskType}, #{item.createDt}, #{item.namespaceId})
</foreach>
</insert>
<!-- 重试统计 -->
<select id="retrySummaryRetryTaskLogList"
resultType="com.aizuda.easy.retry.template.datasource.persistence.dataobject.DashboardRetryResponseDO">
SELECT namespace_id AS namespaceId,
group_name AS groupName,
scene_name AS sceneName,
SUM(CASE WHEN (retry_status = 0) THEN 1 ELSE 0 END) AS runningNum,
SUM(CASE WHEN (retry_status = 1) THEN 1 ELSE 0 END) AS finishNum,
SUM(CASE WHEN (retry_status = 2) THEN 1 ELSE 0 END) AS maxCountNum,
SUM(CASE WHEN (retry_status = 3) THEN 1 ELSE 0 END) AS suspendNum
FROM retry_task_log
WHERE create_dt between #{from} and #{to}
GROUP BY namespace_id, group_name, scene_name
</select>
</mapper>

View File

@ -0,0 +1,64 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.aizuda.easy.retry.template.datasource.persistence.mapper.RetryTaskMapper">
<resultMap id="BaseResultMap" type="com.aizuda.easy.retry.template.datasource.persistence.po.RetryTask">
<id column="id" jdbcType="BIGINT" property="id" />
<result column="namespace_id" jdbcType="VARCHAR" property="namespaceId"/>
<result column="unique_id" jdbcType="VARCHAR" property="uniqueId"/>
<result column="group_name" jdbcType="VARCHAR" property="groupName" />
<result column="scene_name" jdbcType="VARCHAR" property="sceneName" />
<result column="idempotent_id" jdbcType="VARCHAR" property="idempotentId" />
<result column="biz_no" jdbcType="VARCHAR" property="bizNo" />
<result column="executor_name" jdbcType="VARCHAR" property="executorName" />
<result column="args_str" jdbcType="VARCHAR" property="argsStr" />
<result column="ext_attrs" jdbcType="VARCHAR" property="extAttrs" />
<result column="next_trigger_at" jdbcType="TIMESTAMP" property="nextTriggerAt" />
<result column="retry_count" jdbcType="TINYINT" property="retryCount" />
<result column="retry_status" jdbcType="TINYINT" property="retryStatus" />
<result column="task_type" jdbcType="TINYINT" property="taskType"/>
<result column="create_dt" jdbcType="TIMESTAMP" property="createDt" />
<result column="update_dt" jdbcType="TIMESTAMP" property="updateDt" />
</resultMap>
<sql id="Base_Column_List">
id, namespace_id, unique_id, group_name, scene_name, idempotent_id, biz_no, executor_name, args_str, ext_attrs, next_trigger_at, retry_count, retry_status,
create_dt, update_dt, task_type
</sql>
<!-- 定义批量新增的 SQL 映射 -->
<insert id="batchInsert" parameterType="java.util.List">
INSERT INTO retry_task (namespace_id, unique_id, group_name, scene_name, idempotent_id, biz_no, executor_name, args_str, ext_attrs, next_trigger_at, task_type, retry_status, create_dt)
VALUES
<foreach collection="list" item="item" separator=",">
(
#{item.namespaceId},
#{item.uniqueId},
#{item.groupName},
#{item.sceneName},
#{item.idempotentId},
#{item.bizNo},
#{item.executorName},
#{item.argsStr},
#{item.extAttrs},
#{item.nextTriggerAt},
#{item.taskType},
#{item.retryStatus},
#{item.createDt}
)
</foreach>
</insert>
<update id="updateBatchNextTriggerAtById" parameterType="java.util.List">
UPDATE target
SET target.next_trigger_at = src.next_trigger_at
FROM retry_task_${partition} as target
JOIN (
<foreach collection="list" item="item" index="index" separator=" UNION ALL ">
SELECT
#{item.nextTriggerAt} AS next_trigger_at,
#{item.id} AS id
</foreach>
) AS src
ON target.id = src.id;
</update>
</mapper>

View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.aizuda.easy.retry.template.datasource.persistence.mapper.SceneConfigMapper">
<resultMap id="BaseResultMap" type="com.aizuda.easy.retry.template.datasource.persistence.po.SceneConfig">
<id column="id" jdbcType="BIGINT" property="id" />
<result column="scene_name" jdbcType="VARCHAR" property="sceneName" />
<result column="group_name" jdbcType="VARCHAR" property="groupName" />
<result column="scene_status" jdbcType="TINYINT" property="sceneStatus" />
<result column="max_retry_count" jdbcType="TINYINT" property="maxRetryCount" />
<result column="back_off" jdbcType="TINYINT" property="backOff" />
<result column="trigger_interval" jdbcType="TINYINT" property="triggerInterval" />
<result column="deadline_request" jdbcType="BIGINT" property="deadlineRequest" />
<result column="description" jdbcType="VARCHAR" property="description" />
<result column="create_dt" jdbcType="TIMESTAMP" property="createDt" />
<result column="update_dt" jdbcType="TIMESTAMP" property="updateDt" />
</resultMap>
<sql id="Base_Column_List">
id, scene_name, group_name, scene_status, max_retry_count, back_off, `trigger_interval`, deadline_request, description, create_dt, update_dt
</sql>
</mapper>

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.aizuda.easy.retry.template.datasource.persistence.mapper.SequenceAllocMapper">
<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="com.aizuda.easy.retry.template.datasource.persistence.po.SequenceAlloc">
<id column="id" property="id" />
<result column="group_name" property="groupName" />
<result column="max_id" property="maxId" />
<result column="step" property="step" />
<result column="update_dt" property="updateDt" />
</resultMap>
<update id="updateMaxIdByCustomStep">
UPDATE sequence_alloc
SET max_id = max_id + #{step}, update_dt = now()
WHERE group_name = #{groupName} and namespace_id = #{namespaceId}
</update>
<update id="updateMaxId">
UPDATE sequence_alloc
SET max_id = max_id + step, update_dt = now()
WHERE group_name = #{groupName} and namespace_id = #{namespaceId}
</update>
</mapper>

View File

@ -0,0 +1,67 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.aizuda.easy.retry.template.datasource.persistence.mapper.ServerNodeMapper">
<resultMap id="BaseResultMap" type="com.aizuda.easy.retry.template.datasource.persistence.po.ServerNode">
<id column="id" jdbcType="BIGINT" property="id" />
<result column="namespace_id" jdbcType="VARCHAR" property="namespaceId" />
<result column="group_name" jdbcType="VARCHAR" property="groupName" />
<result column="host_id" jdbcType="VARCHAR" property="hostId" />
<result column="host_ip" jdbcType="VARCHAR" property="hostIp" />
<result column="host_port" jdbcType="INTEGER" property="hostPort" />
<result column="expire_at" jdbcType="TIMESTAMP" property="expireAt" />
<result column="node_type" jdbcType="TINYINT" property="nodeType" />
<result column="context_path" jdbcType="VARCHAR" property="contextPath" />
<result column="ext_attrs" jdbcType="VARCHAR" property="extAttrs" />
<result column="create_dt" jdbcType="TIMESTAMP" property="createDt" />
<result column="update_dt" jdbcType="TIMESTAMP" property="updateDt" />
</resultMap>
<sql id="Base_Column_List">
id, namespace_id, group_name, context_path, host_id, host_ip, host_port, expire_at, node_type,create_dt,update_dt
</sql>
<insert id="insertOrUpdate" parameterType="java.util.List" useGeneratedKeys="true" keyProperty="id">
MERGE INTO server_node AS target
USING (
VALUES
<foreach collection="records" item="item" index="index" separator=",">
(
#{item.namespaceId,jdbcType=VARCHAR}, #{item.groupName,jdbcType=VARCHAR},
#{item.hostId,jdbcType=VARCHAR}, #{item.hostIp,jdbcType=VARCHAR}, #{item.hostPort,jdbcType=INTEGER},
#{item.expireAt,jdbcType=TIMESTAMP}, #{item.nodeType,jdbcType=TINYINT}, #{item.extAttrs,jdbcType=VARCHAR},
#{item.contextPath,jdbcType=VARCHAR}, #{item.createDt,jdbcType=TIMESTAMP}
)
</foreach>
) AS source (namespace_id, group_name, host_id, host_ip, host_port,
expire_at, node_type, ext_attrs, context_path, create_dt)
ON target.namespace_id = source.namespace_id
AND target.group_name = source.group_name
AND target.host_id = source.host_id
WHEN MATCHED THEN
UPDATE SET
target.expire_at = source.expire_at, target.update_dt = GETDATE()
WHEN NOT MATCHED THEN
INSERT (namespace_id, group_name, host_id, host_ip, host_port,
expire_at, node_type, ext_attrs, context_path, create_dt, update_dt)
VALUES (source.namespace_id, source.group_name, source.host_id, source.host_ip, source.host_port,
source.expire_at, source.node_type, source.ext_attrs, source.context_path, source.create_dt, GETDATE());
</insert>
<delete id="deleteByExpireAt">
DELETE FROM server_node
WHERE expire_at &lt;= #{endTime,jdbcType=TIMESTAMP}
</delete>
<select id="countActivePod"
resultType="com.aizuda.easy.retry.template.datasource.persistence.dataobject.ActivePodQuantityResponseDO">
SELECT
node_type AS nodeType,
COUNT(*) AS total
FROM server_node
WHERE namespace_id IN
<foreach collection="namespaceIds" item="namespaceId" separator="," open="(" close=")">
#{namespaceId}
</foreach>
GROUP BY node_type
</select>
</mapper>

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.aizuda.easy.retry.template.datasource.persistence.mapper.SystemUserMapper">
<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="com.aizuda.easy.retry.template.datasource.persistence.po.SystemUser">
<id column="id" property="id" />
<result column="username" property="username" />
<result column="password" property="password" />
<result column="role" property="role" />
<result column="create_dt" property="createDt" />
<result column="update_dt" property="updateDt" />
</resultMap>
</mapper>

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.aizuda.easy.retry.template.datasource.persistence.mapper.SystemUserPermissionMapper">
<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="com.aizuda.easy.retry.template.datasource.persistence.po.SystemUserPermission">
<id column="id" property="id" />
<result column="group_name" property="groupName" />
<result column="system_user_id" property="systemUserId" />
<result column="namespace_id" property="namespaceId" />
<result column="create_dt" property="createDt" />
</resultMap>
</mapper>

View File

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.aizuda.easy.retry.template.datasource.persistence.mapper.WorkflowMapper">
<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="com.aizuda.easy.retry.template.datasource.persistence.po.Workflow">
<id column="id" property="id" />
<result column="namespace_id" property="namespaceId" />
<result column="group_name" property="groupName" />
<result column="workflow_status" property="workflowStatus" />
<result column="next_trigger_at" property="nextTriggerAt" />
<result column="flow_info" property="flowInfo" />
<result column="create_dt" property="createDt" />
<result column="update_dt" property="updateDt" />
<result column="deleted" property="deleted" />
<result column="ext_attrs" property="extAttrs" />
</resultMap>
<update id="updateBatchNextTriggerAtById" parameterType="java.util.List">
UPDATE workflow
SET workflow.next_trigger_at = src.next_trigger_at
FROM workflow
JOIN (
<foreach collection="list" item="item" index="index" separator=" UNION ALL ">
SELECT
#{item.nextTriggerAt} AS next_trigger_at,
#{item.id} AS id
</foreach>
) AS src ON workflow.id = src.id;
</update>
</mapper>

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.aizuda.easy.retry.template.datasource.persistence.mapper.WorkflowNodeMapper">
<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="com.aizuda.easy.retry.template.datasource.persistence.po.WorkflowNode">
<id column="id" property="id" />
<result column="namespace_id" property="namespaceId" />
<result column="group_name" property="groupName" />
<result column="job_id" property="jobId" />
<result column="node_type" property="nodeType" />
<result column="expression_type" property="expressionType" />
<result column="fail_strategy" property="failStrategy" />
<result column="workflow_node_status" property="workflowNodeStatus" />
<result column="node_expression" property="nodeExpression" />
<result column="create_dt" property="createDt" />
<result column="update_dt" property="updateDt" />
<result column="deleted" property="deleted" />
<result column="ext_attrs" property="extAttrs" />
</resultMap>
</mapper>

View File

@ -0,0 +1,50 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.aizuda.easy.retry.template.datasource.persistence.mapper.WorkflowTaskBatchMapper">
<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="com.aizuda.easy.retry.template.datasource.persistence.po.WorkflowTaskBatch">
<id column="id" property="id"/>
<result column="namespace_id" property="namespaceId"/>
<result column="group_name" property="groupName"/>
<result column="workflow_id" property="workflowId"/>
<result column="task_batch_status" property="taskBatchStatus"/>
<result column="operation_reason" property="operationReason"/>
<result column="execution_at" property="executionAt"/>
<result column="create_dt" property="createDt"/>
<result column="update_dt" property="updateDt"/>
<result column="deleted" property="deleted"/>
<result column="ext_attrs" property="extAttrs"/>
</resultMap>
<select id="selectWorkflowBatchPageList"
parameterType="com.aizuda.easy.retry.template.datasource.persistence.dataobject.WorkflowBatchQueryDO"
resultType="com.aizuda.easy.retry.template.datasource.persistence.dataobject.WorkflowBatchResponseDO">
SELECT
a.*,
b.workflow_name
FROM workflow_task_batch a
JOIN workflow b ON a.workflow_id = b.id
<where>
a.namespace_id = #{queryDO.namespaceId}
<if test="queryDO.workflowId != null">
AND a.workflow_id = #{queryDO.workflowId}
</if>
<if test="queryDO.groupNames != null and queryDO.groupNames.size > 0">
AND a.group_name IN
<foreach collection="queryDO.groupNames" item="groupName" open="(" separator="," close=")">
#{groupName}
</foreach>
</if>
<if test="queryDO.taskBatchStatus != null">
AND task_batch_status = #{queryDO.taskBatchStatus}
</if>
<if test="queryDO.workflowName != null">
AND b.workflow_name LIKE #{queryDO.workflowName}
</if>
AND a.deleted = 0
</where>
ORDER BY a.id DESC
</select>
</mapper>

View File

@ -25,6 +25,7 @@
<module>easy-retry-mysql-datasource</module>
<module>easy-retry-postgres-datasource</module>
<module>easy-retry-oracle-datasource</module>
<module>easy-retry-sqlserver-datasource</module>
<module>easy-retry-datasource-template</module>
</modules>

View File

@ -39,10 +39,12 @@ import java.util.List;
@RequiredArgsConstructor
public class JdbcLockProvider implements LockStorage, Lifecycle {
protected static final List<String> ALLOW_DB = Arrays.asList(DbTypeEnum.MYSQL.getDb(),
protected static final List<String> ALLOW_DB = Arrays.asList(
DbTypeEnum.MYSQL.getDb(),
DbTypeEnum.MARIADB.getDb(),
DbTypeEnum.POSTGRES.getDb(),
DbTypeEnum.ORACLE.getDb());
DbTypeEnum.ORACLE.getDb(),
DbTypeEnum.SQLSERVER.getDb());
private final DistributedLockMapper distributedLockMapper;

View File

@ -105,7 +105,8 @@ public class RetryTaskMoreThresholdAlarmSchedule extends AbstractSchedule implem
List<NotifyConfig> notifyConfigs = accessTemplate.getNotifyConfigAccess()
.listPage(new PageDTO<>(startId, 1000), new LambdaQueryWrapper<NotifyConfig>()
.eq(NotifyConfig::getNotifyStatus, StatusEnum.YES.getStatus())
.eq(NotifyConfig::getNotifyScene, NotifySceneEnum.MAX_RETRY.getNotifyScene()))
.eq(NotifyConfig::getNotifyScene, NotifySceneEnum.MAX_RETRY.getNotifyScene())
.orderByDesc(NotifyConfig::getId)) // SQLServer 分页必须 ORDER BY
.getRecords();
return RetryTaskConverter.INSTANCE.toNotifyConfigPartitionTask(notifyConfigs);

View File

@ -22,6 +22,11 @@ spring:
# url: jdbc:oracle:thin:@//localhost:1521/XEPDB1
# username: root
# password: root
## SQL Server
# driverClassName: com.microsoft.sqlserver.jdbc.SQLServerDriver
# url: jdbc:sqlserver://localhost:1433;DatabaseName=easy_retry;SelectMethod=cursor;encrypt=false;rewriteBatchedStatements=true
# username: SA
# password: EasyRetry@24
type: com.zaxxer.hikari.HikariDataSource
hikari:
connection-timeout: 30000

View File

@ -59,6 +59,10 @@
<groupId>com.aizuda</groupId>
<artifactId>easy-retry-oracle-datasource</artifactId>
</dependency>
<dependency>
<groupId>com.aizuda</groupId>
<artifactId>easy-retry-sqlserver-datasource</artifactId>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>

View File

@ -2,10 +2,11 @@ package com.aizuda.easy.retry.server.web.service.impl;
import cn.hutool.core.util.StrUtil;
import com.aizuda.easy.retry.common.core.enums.NodeTypeEnum;
import com.aizuda.easy.retry.common.core.util.NetUtil;
import com.aizuda.easy.retry.common.log.EasyRetryLog;
import com.aizuda.easy.retry.common.core.model.Result;
import com.aizuda.easy.retry.common.core.util.JsonUtil;
import com.aizuda.easy.retry.common.core.util.NetUtil;
import com.aizuda.easy.retry.common.log.EasyRetryLog;
import com.aizuda.easy.retry.server.common.config.SystemProperties;
import com.aizuda.easy.retry.server.common.dto.DistributeInstance;
import com.aizuda.easy.retry.server.common.dto.ServerNodeExtAttrs;
import com.aizuda.easy.retry.server.common.register.ServerRegister;
@ -21,6 +22,7 @@ import com.aizuda.easy.retry.server.web.model.response.ServerNodeResponseVO;
import com.aizuda.easy.retry.server.web.service.DashBoardService;
import com.aizuda.easy.retry.server.web.service.convert.*;
import com.aizuda.easy.retry.server.web.util.UserSessionUtils;
import com.aizuda.easy.retry.template.datasource.enums.DbTypeEnum;
import com.aizuda.easy.retry.template.datasource.persistence.dataobject.ActivePodQuantityResponseDO;
import com.aizuda.easy.retry.template.datasource.persistence.dataobject.DashboardCardResponseDO;
import com.aizuda.easy.retry.template.datasource.persistence.dataobject.DashboardLineResponseDO;
@ -37,12 +39,10 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.PageDTO;
import com.google.common.collect.Lists;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.web.client.RestTemplate;
import java.text.MessageFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
@ -59,11 +59,14 @@ import java.util.stream.Collectors;
@Slf4j
@RequiredArgsConstructor
public class DashBoardServiceImpl implements DashBoardService {
private static final String DASHBOARD_CONSUMER_BUCKET = "/dashboard/consumer/bucket";
private final SystemProperties systemProperties;
private final ServerNodeMapper serverNodeMapper;
private final RestTemplate restTemplate;
private final JobSummaryMapper jobSummaryMapper;
private final RetrySummaryMapper retrySummaryMapper;
private static final String DASHBOARD_CONSUMER_BUCKET = "/dashboard/consumer/bucket";
@Override
public DashboardCardResponseVO taskRetryJob() {
@ -86,7 +89,7 @@ public class DashBoardServiceImpl implements DashBoardService {
List<DashboardCardResponseDO.RetryTask> retryTaskList = retrySummaryMapper.retryTaskBarList(namespaceId, groupNames);
Map<LocalDateTime, LongSummaryStatistics> summaryStatisticsMap = retryTaskList.stream().collect(Collectors.groupingBy(DashboardCardResponseDO.RetryTask::getTriggerAt,
Collectors.summarizingLong(i -> i.getMaxCountNum() + i.getRunningNum() + i.getSuspendNum() + i.getFinishNum())));
Collectors.summarizingLong(i -> i.getMaxCountNum() + i.getRunningNum() + i.getSuspendNum() + i.getFinishNum())));
for (Map.Entry<LocalDateTime, LongSummaryStatistics> map : summaryStatisticsMap.entrySet()) {
if (retryTaskBarMap.containsKey(LocalDateTime.of(map.getKey().toLocalDate(), LocalTime.MIN))) {
DashboardCardResponseVO.RetryTaskBar retryTaskBar = retryTaskBarMap.get(LocalDateTime.of(map.getKey().toLocalDate(), LocalTime.MIN));
@ -115,7 +118,12 @@ public class DashBoardServiceImpl implements DashBoardService {
List<String> groupNames = userSessionVO.isUser() ? userSessionVO.getGroupNames() : new ArrayList<>();
DashboardRetryLineResponseVO dashboardRetryLineResponseVO = new DashboardRetryLineResponseVO();
// 重试任务列表
IPage<DashboardRetryLineResponseDO.Task> IPage = retrySummaryMapper.retryTaskList(namespaceId, groupNames, new Page<>(baseQueryVO.getPage(), baseQueryVO.getSize()));
Page<Object> pager = new Page<>(baseQueryVO.getPage(), baseQueryVO.getSize());
// 针对SQL Server的分页COUNT, 自定义statement ID
if (DbTypeEnum.SQLSERVER.equals(systemProperties.getDbType())) {
pager.setCountId("sqlServer_jobTaskList_Count");
}
IPage<DashboardRetryLineResponseDO.Task> IPage = retrySummaryMapper.retryTaskList(namespaceId, groupNames, pager);
List<DashboardRetryLineResponseVO.Task> taskList = JobSummaryResponseVOConverter.INSTANCE.toDashboardRetryLineResponseVO(IPage.getRecords());
PageResult<List<DashboardRetryLineResponseVO.Task>> pageResult = new PageResult<>(new PageDTO(IPage.getCurrent(), IPage.getSize(), IPage.getTotal()), taskList);
dashboardRetryLineResponseVO.setTaskList(pageResult);
@ -146,7 +154,12 @@ public class DashBoardServiceImpl implements DashBoardService {
List<String> groupNames = userSessionVO.isUser() ? userSessionVO.getGroupNames() : new ArrayList<>();
DashboardRetryLineResponseVO dashboardRetryLineResponseVO = new DashboardRetryLineResponseVO();
// 重试任务列表
IPage<DashboardRetryLineResponseDO.Task> IPage = jobSummaryMapper.jobTaskList(namespaceId, groupNames, new Page<>(baseQueryVO.getPage(), baseQueryVO.getSize()));
Page<Object> pager = new Page<>(baseQueryVO.getPage(), baseQueryVO.getSize());
// 针对SQL Server的分页COUNT, 自定义statement ID
if (DbTypeEnum.SQLSERVER.equals(systemProperties.getDbType())) {
pager.setCountId("sqlServer_jobTaskList_Count");
}
IPage<DashboardRetryLineResponseDO.Task> IPage = jobSummaryMapper.jobTaskList(namespaceId, groupNames, pager);
List<DashboardRetryLineResponseVO.Task> taskList = JobSummaryResponseVOConverter.INSTANCE.toDashboardRetryLineResponseVO(IPage.getRecords());
PageResult<List<DashboardRetryLineResponseVO.Task>> pageResult = new PageResult<>(new PageDTO(IPage.getCurrent(), IPage.getSize(), IPage.getTotal()), taskList);
dashboardRetryLineResponseVO.setTaskList(pageResult);
@ -174,7 +187,7 @@ public class DashBoardServiceImpl implements DashBoardService {
LambdaQueryWrapper<ServerNode> serverNodeLambdaQueryWrapper = new LambdaQueryWrapper<>();
serverNodeLambdaQueryWrapper.in(ServerNode::getNamespaceId, Lists.newArrayList(
UserSessionUtils.currentUserSession().getNamespaceId(), ServerRegister.NAMESPACE_ID
UserSessionUtils.currentUserSession().getNamespaceId(), ServerRegister.NAMESPACE_ID
));
if (StrUtil.isNotBlank(queryVO.getGroupName())) {
serverNodeLambdaQueryWrapper.eq(ServerNode::getGroupName, queryVO.getGroupName());
@ -201,13 +214,13 @@ public class DashBoardServiceImpl implements DashBoardService {
ServerNodeExtAttrs serverNodeExtAttrs = JsonUtil.parseObject(serverNodeResponseVO.getExtAttrs(), ServerNodeExtAttrs.class);
try {
// 从远程节点取
String url = NetUtil.getUrl(serverNodeResponseVO.getHostIp(), serverNodeExtAttrs.getWebPort(), serverNodeResponseVO.getContextPath());
String url = NetUtil.getUrl(serverNodeResponseVO.getHostIp(), serverNodeExtAttrs.getWebPort(), serverNodeResponseVO.getContextPath());
Result<List<Integer>> result = restTemplate.getForObject(url.concat(DASHBOARD_CONSUMER_BUCKET), Result.class);
List<Integer> data = result.getData();
if (!CollectionUtils.isEmpty(data)) {
serverNodeResponseVO.setConsumerBuckets(data.stream()
.sorted(Integer::compareTo)
.collect(Collectors.toCollection(LinkedHashSet::new)));
.sorted(Integer::compareTo)
.collect(Collectors.toCollection(LinkedHashSet::new)));
}
} catch (Exception e) {
EasyRetryLog.LOCAL.error("Failed to retrieve consumer group for node [{}:{}].", serverNodeResponseVO.getHostIp(), serverNodeExtAttrs.getWebPort());

View File

@ -122,7 +122,8 @@ public class JobServiceImpl implements JobService {
queryWrapper.eq(Job::getId, jobId);
}
queryWrapper.eq(Job::getDeleted, StatusEnum.NO.getStatus());
queryWrapper.eq(Job::getDeleted, StatusEnum.NO.getStatus())
.orderByAsc(Job::getId); // SQLServer 分页必须 ORDER BY
PageDTO<Job> pageDTO = new PageDTO<>(1, 20);
PageDTO<Job> selectPage = jobMapper.selectPage(pageDTO, queryWrapper);
return JobResponseVOConverter.INSTANCE.toJobResponseVOs(selectPage.getRecords());

View File

@ -41,6 +41,7 @@ public class JobTaskServiceImpl implements JobTaskService {
queryWrapper.eq(JobTask::getTaskBatchId, queryVO.getTaskBatchId());
}
queryWrapper.orderByAsc(JobTask::getJobId); // SQLServer 分页必须 ORDER BY
PageDTO<JobTask> selectPage = jobTaskMapper.selectPage(pageDTO, queryWrapper);
List<JobTaskResponseVO> jobTaskResponseVOs = JobTaskResponseVOConverter.INSTANCE.toJobTaskResponseVOs(

View File

@ -336,7 +336,8 @@ public class WorkflowServiceImpl implements WorkflowService {
queryWrapper.eq(Workflow::getId, workflowId);
}
queryWrapper.eq(Workflow::getDeleted, StatusEnum.NO.getStatus());
queryWrapper.eq(Workflow::getDeleted, StatusEnum.NO.getStatus())
.orderByAsc(Workflow::getId); // SQLServer 分页必须 ORDER BY
PageDTO<Workflow> pageDTO = new PageDTO<>(1, 20);
PageDTO<Workflow> selectPage = workflowMapper.selectPage(pageDTO, queryWrapper);

View File

@ -15,6 +15,12 @@
<div class="text" :style="{ color: LevelEnum[log.level].color }">
{{ log.level.length === 4 ? log.level + ' ' : log.level }}
</div>
<div v-if="log.host" class="text" style="color: #00a3a3">
[
{{ log.host }}
<template v-if="log.port">:{{ log.port }}</template>
]
</div>
<div class="text" style="color: #00a3a3">[{{ log.thread }}]</div>
<div class="text" style="color: #a771bf; font-weight: 500">{{ log.location }}</div>
<div class="text">:</div>

View File

@ -95,6 +95,11 @@
<artifactId>easy-retry-oracle-datasource</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>com.aizuda</groupId>
<artifactId>easy-retry-sqlserver-datasource</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-http</artifactId>