✨ 添加分布式锁组件.
This commit is contained in:
@@ -11,13 +11,14 @@
|
|||||||
* 🩰 修改 命令执行日志 UI 修改
|
* 🩰 修改 命令执行日志 UI 修改
|
||||||
* 🌈 新增 命令执行模板配置默认主机
|
* 🌈 新增 命令执行模板配置默认主机
|
||||||
* 🌈 新增 主机终端书签路径
|
* 🌈 新增 主机终端书签路径
|
||||||
* 🌈 新增 命令日志添加状态信息 `app.exec-log.append-status`
|
* 🌈 新增 命令执行日志添加 `ansi` 日志 `app.exec-log.append-ansi`
|
||||||
* 🌈 新增 定时删除命令日志文件 `app.exec-log.auto-clear`
|
* 🌈 新增 定时删除命令执行日志文件 `app.exec-log.auto-clear`
|
||||||
* 🔨 优化 通用分组模型添加 `userId`
|
* 🔨 优化 通用分组模型添加 `userId`
|
||||||
* 🔨 优化 退出登录不重定向
|
* 🔨 优化 退出登录不重定向
|
||||||
* 🔨 优化 动态设置页面标题
|
* 🔨 优化 动态设置页面标题
|
||||||
* 🔨 优化 终端断开后回车重连
|
* 🔨 优化 终端断开后回车重连
|
||||||
* 🔨 优化 自动删除未使用的命令片段分组
|
* 🔨 优化 自动删除未使用的命令片段分组
|
||||||
|
* 🔨 优化 添加分布式锁工具类
|
||||||
|
|
||||||
## v1.0.5
|
## v1.0.5
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
> ##### 5. 调度任务、批量执行 的日志文件中如何只保存原始输出?
|
> ##### 5. 调度任务、批量执行 的日志文件中如何只保存原始输出?
|
||||||
|
|
||||||
修改 application.yaml `app.exec-log.append-status` 为 false
|
修改 application.yaml `app.exec-log.append-ansi` 为 false
|
||||||
|
|
||||||
> ##### 6. 为什么使用秘钥认证还是无法连接机器?
|
> ##### 6. 为什么使用秘钥认证还是无法连接机器?
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,10 @@ package com.orion.ops.framework.redis.configuration;
|
|||||||
|
|
||||||
import com.orion.ops.framework.common.constant.AutoConfigureOrderConst;
|
import com.orion.ops.framework.common.constant.AutoConfigureOrderConst;
|
||||||
import com.orion.ops.framework.redis.configuration.config.RedissonConfig;
|
import com.orion.ops.framework.redis.configuration.config.RedissonConfig;
|
||||||
|
import com.orion.ops.framework.redis.core.lock.RedisLocker;
|
||||||
|
import com.orion.ops.framework.redis.core.utils.RedisLocks;
|
||||||
import com.orion.ops.framework.redis.core.utils.RedisUtils;
|
import com.orion.ops.framework.redis.core.utils.RedisUtils;
|
||||||
|
import org.redisson.api.RedissonClient;
|
||||||
import org.redisson.spring.starter.RedissonAutoConfigurationCustomizer;
|
import org.redisson.spring.starter.RedissonAutoConfigurationCustomizer;
|
||||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||||
import org.springframework.boot.autoconfigure.AutoConfigureOrder;
|
import org.springframework.boot.autoconfigure.AutoConfigureOrder;
|
||||||
@@ -56,5 +59,16 @@ public class OrionRedisAutoConfiguration {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param redissonClient redissonClient
|
||||||
|
* @return redis 分布式锁
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
public RedisLocker redisLocker(RedissonClient redissonClient) {
|
||||||
|
RedisLocker redisLocker = new RedisLocker(redissonClient);
|
||||||
|
RedisLocks.setRedisLocker(redisLocker);
|
||||||
|
return redisLocker;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,74 @@
|
|||||||
|
package com.orion.ops.framework.redis.core.lock;
|
||||||
|
|
||||||
|
import com.orion.lang.utils.Exceptions;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.redisson.api.RLock;
|
||||||
|
import org.redisson.api.RedissonClient;
|
||||||
|
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* redis 分布式锁
|
||||||
|
*
|
||||||
|
* @author Jiahang Li
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 2024/4/25 16:42
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
public class RedisLocker {
|
||||||
|
|
||||||
|
private final RedissonClient redissonClient;
|
||||||
|
|
||||||
|
public RedisLocker(RedissonClient redissonClient) {
|
||||||
|
this.redissonClient = redissonClient;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 尝试获取锁
|
||||||
|
*
|
||||||
|
* @param key key
|
||||||
|
* @param run run
|
||||||
|
* @return 是否获取到锁
|
||||||
|
*/
|
||||||
|
public boolean tryLock(String key, Runnable run) {
|
||||||
|
// 获取锁
|
||||||
|
RLock lock = redissonClient.getLock(key);
|
||||||
|
// 未获取到直接返回
|
||||||
|
if (!lock.tryLock()) {
|
||||||
|
log.info("RedisLocks.tryLock failed {}", key);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// 执行
|
||||||
|
try {
|
||||||
|
run.run();
|
||||||
|
} finally {
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 尝试获取锁
|
||||||
|
*
|
||||||
|
* @param key key
|
||||||
|
* @param call call
|
||||||
|
* @param <T> T
|
||||||
|
* @return 执行结果
|
||||||
|
*/
|
||||||
|
public <T> T tryLock(String key, Supplier<T> call) {
|
||||||
|
// 获取锁
|
||||||
|
RLock lock = redissonClient.getLock(key);
|
||||||
|
// 未获取到直接返回
|
||||||
|
if (!lock.tryLock()) {
|
||||||
|
log.info("RedisLocks.tryLock failed {}", key);
|
||||||
|
throw Exceptions.lock();
|
||||||
|
}
|
||||||
|
// 执行
|
||||||
|
try {
|
||||||
|
return call.get();
|
||||||
|
} finally {
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
package com.orion.ops.framework.redis.core.utils;
|
||||||
|
|
||||||
|
import com.orion.lang.utils.Exceptions;
|
||||||
|
import com.orion.ops.framework.redis.core.lock.RedisLocker;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* redis 分布式锁工具类
|
||||||
|
*
|
||||||
|
* @author Jiahang Li
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 2024/4/25 16:42
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
public class RedisLocks {
|
||||||
|
|
||||||
|
private static RedisLocker redisLocker;
|
||||||
|
|
||||||
|
private RedisLocks() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 尝试获取锁
|
||||||
|
*
|
||||||
|
* @param key key
|
||||||
|
* @param run run
|
||||||
|
* @return 是否获取到锁
|
||||||
|
*/
|
||||||
|
public static boolean tryLock(String key, Runnable run) {
|
||||||
|
return redisLocker.tryLock(key, run);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 尝试获取锁
|
||||||
|
*
|
||||||
|
* @param key key
|
||||||
|
* @param call call
|
||||||
|
* @param <T> T
|
||||||
|
* @return 执行结果
|
||||||
|
*/
|
||||||
|
public static <T> T tryLock(String key, Supplier<T> call) {
|
||||||
|
return redisLocker.tryLock(key, call);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setRedisLocker(RedisLocker redisLocker) {
|
||||||
|
if (RedisLocks.redisLocker != null) {
|
||||||
|
// unmodified
|
||||||
|
throw Exceptions.state();
|
||||||
|
}
|
||||||
|
RedisLocks.redisLocker = redisLocker;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -179,12 +179,12 @@ app:
|
|||||||
backup-file-name: bk_${fileName}_${timestamp}
|
backup-file-name: bk_${fileName}_${timestamp}
|
||||||
# 执行日志
|
# 执行日志
|
||||||
exec-log:
|
exec-log:
|
||||||
# 是否拼接执行状态
|
# 是否拼接 ansi 执行状态日志
|
||||||
append-status: true
|
append-ansi: true
|
||||||
# 自动清理执行文件
|
# 自动清理执行文件
|
||||||
auto-clear: true
|
auto-clear: true
|
||||||
# 保留周期
|
# 保留周期 (天)
|
||||||
keep-period: 0
|
keep-period: 60
|
||||||
|
|
||||||
# orion framework config
|
# orion framework config
|
||||||
orion:
|
orion:
|
||||||
|
|||||||
@@ -17,9 +17,9 @@ import org.springframework.stereotype.Component;
|
|||||||
public class AppExecLogConfig {
|
public class AppExecLogConfig {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 是否拼接执行状态
|
* 是否拼接 ansi 执行状态日志
|
||||||
*/
|
*/
|
||||||
private Boolean appendStatus;
|
private Boolean appendAnsi;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 自动清理执行文件
|
* 自动清理执行文件
|
||||||
@@ -32,9 +32,9 @@ public class AppExecLogConfig {
|
|||||||
private Integer keepPeriod;
|
private Integer keepPeriod;
|
||||||
|
|
||||||
public AppExecLogConfig() {
|
public AppExecLogConfig() {
|
||||||
this.appendStatus = true;
|
this.appendAnsi = true;
|
||||||
this.autoClear = true;
|
this.autoClear = true;
|
||||||
this.keepPeriod = 90;
|
this.keepPeriod = 60;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
package com.orion.ops.module.asset.task;
|
package com.orion.ops.module.asset.task;
|
||||||
|
|
||||||
|
import com.orion.ops.framework.redis.core.utils.RedisLocks;
|
||||||
import com.orion.ops.module.asset.service.CommandSnippetGroupService;
|
import com.orion.ops.module.asset.service.CommandSnippetGroupService;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.redisson.api.RLock;
|
|
||||||
import org.redisson.api.RedissonClient;
|
|
||||||
import org.springframework.scheduling.annotation.Scheduled;
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
@@ -25,9 +24,6 @@ public class CommandSnippetGroupAutoClearTask {
|
|||||||
*/
|
*/
|
||||||
private static final String LOCK_KEY = "clear:csg:lock";
|
private static final String LOCK_KEY = "clear:csg:lock";
|
||||||
|
|
||||||
@Resource
|
|
||||||
private RedissonClient redissonClient;
|
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private CommandSnippetGroupService commandSnippetGroupService;
|
private CommandSnippetGroupService commandSnippetGroupService;
|
||||||
|
|
||||||
@@ -37,22 +33,9 @@ public class CommandSnippetGroupAutoClearTask {
|
|||||||
@Scheduled(cron = "0 10 2 * * ?")
|
@Scheduled(cron = "0 10 2 * * ?")
|
||||||
public void clear() {
|
public void clear() {
|
||||||
log.info("CommandSnippetGroupAutoClearTask.clear start");
|
log.info("CommandSnippetGroupAutoClearTask.clear start");
|
||||||
// 获取锁
|
// 获取锁并清理
|
||||||
RLock lock = redissonClient.getLock(LOCK_KEY);
|
RedisLocks.tryLock(LOCK_KEY, commandSnippetGroupService::clearUnusedGroup);
|
||||||
// 未获取到直接返回
|
|
||||||
if (!lock.tryLock()) {
|
|
||||||
log.info("CommandSnippetGroupAutoClearTask.clear locked end");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
// 清理
|
|
||||||
commandSnippetGroupService.clearUnusedGroup();
|
|
||||||
log.info("CommandSnippetGroupAutoClearTask.clear finish");
|
log.info("CommandSnippetGroupAutoClearTask.clear finish");
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("CommandSnippetGroupAutoClearTask.clear error", e);
|
|
||||||
} finally {
|
|
||||||
lock.unlock();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,12 +4,11 @@ import com.orion.lang.utils.Strings;
|
|||||||
import com.orion.lang.utils.io.Files1;
|
import com.orion.lang.utils.io.Files1;
|
||||||
import com.orion.lang.utils.time.Dates;
|
import com.orion.lang.utils.time.Dates;
|
||||||
import com.orion.ops.framework.common.file.FileClient;
|
import com.orion.ops.framework.common.file.FileClient;
|
||||||
|
import com.orion.ops.framework.redis.core.utils.RedisLocks;
|
||||||
import com.orion.ops.module.asset.dao.ExecHostLogDAO;
|
import com.orion.ops.module.asset.dao.ExecHostLogDAO;
|
||||||
import com.orion.ops.module.asset.define.config.AppExecLogConfig;
|
import com.orion.ops.module.asset.define.config.AppExecLogConfig;
|
||||||
import com.orion.ops.module.asset.entity.domain.ExecHostLogDO;
|
import com.orion.ops.module.asset.entity.domain.ExecHostLogDO;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.redisson.api.RLock;
|
|
||||||
import org.redisson.api.RedissonClient;
|
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||||
import org.springframework.scheduling.annotation.Scheduled;
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
@@ -38,9 +37,6 @@ public class ExecLogFileAutoClearTask {
|
|||||||
@Resource
|
@Resource
|
||||||
private AppExecLogConfig appExecLogConfig;
|
private AppExecLogConfig appExecLogConfig;
|
||||||
|
|
||||||
@Resource
|
|
||||||
private RedissonClient redissonClient;
|
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private FileClient logsFileClient;
|
private FileClient logsFileClient;
|
||||||
|
|
||||||
@@ -50,26 +46,12 @@ public class ExecLogFileAutoClearTask {
|
|||||||
/**
|
/**
|
||||||
* 清理
|
* 清理
|
||||||
*/
|
*/
|
||||||
// @Scheduled(cron = "0 0 3 * * ?")
|
@Scheduled(cron = "0 0 3 * * ?")
|
||||||
@Scheduled(fixedRate = 20000)
|
|
||||||
public void clear() {
|
public void clear() {
|
||||||
log.info("ExecLogFileAutoClearTask.clear start");
|
log.info("ExecLogFileAutoClearTask.clear start");
|
||||||
// 获取锁
|
// 获取锁并且执行
|
||||||
RLock lock = redissonClient.getLock(LOCK_KEY);
|
RedisLocks.tryLock(LOCK_KEY, this::doClearFile);
|
||||||
// 未获取到直接返回
|
|
||||||
if (!lock.tryLock()) {
|
|
||||||
log.info("ExecLogFileAutoClearTask.clear locked end");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
// 清理
|
|
||||||
this.doClearFile();
|
|
||||||
log.info("ExecLogFileAutoClearTask.clear finish");
|
log.info("ExecLogFileAutoClearTask.clear finish");
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("ExecLogFileAutoClearTask.clear error", e);
|
|
||||||
} finally {
|
|
||||||
lock.unlock();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
package com.orion.ops.module.asset.task;
|
package com.orion.ops.module.asset.task;
|
||||||
|
|
||||||
|
import com.orion.ops.framework.redis.core.utils.RedisLocks;
|
||||||
import com.orion.ops.module.asset.service.PathBookmarkGroupService;
|
import com.orion.ops.module.asset.service.PathBookmarkGroupService;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.redisson.api.RLock;
|
|
||||||
import org.redisson.api.RedissonClient;
|
|
||||||
import org.springframework.scheduling.annotation.Scheduled;
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
@@ -25,9 +24,6 @@ public class PathBookmarkGroupAutoClearTask {
|
|||||||
*/
|
*/
|
||||||
private static final String LOCK_KEY = "clear:pbg:lock";
|
private static final String LOCK_KEY = "clear:pbg:lock";
|
||||||
|
|
||||||
@Resource
|
|
||||||
private RedissonClient redissonClient;
|
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private PathBookmarkGroupService pathBookmarkGroupService;
|
private PathBookmarkGroupService pathBookmarkGroupService;
|
||||||
|
|
||||||
@@ -37,22 +33,9 @@ public class PathBookmarkGroupAutoClearTask {
|
|||||||
@Scheduled(cron = "0 20 2 * * ?")
|
@Scheduled(cron = "0 20 2 * * ?")
|
||||||
public void clear() {
|
public void clear() {
|
||||||
log.info("PathBookmarkGroupAutoClearTask.clear start");
|
log.info("PathBookmarkGroupAutoClearTask.clear start");
|
||||||
// 获取锁
|
// 获取锁并清理
|
||||||
RLock lock = redissonClient.getLock(LOCK_KEY);
|
RedisLocks.tryLock(LOCK_KEY, pathBookmarkGroupService::clearUnusedGroup);
|
||||||
// 未获取到直接返回
|
|
||||||
if (!lock.tryLock()) {
|
|
||||||
log.info("PathBookmarkGroupAutoClearTask.clear locked end");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
// 清理
|
|
||||||
pathBookmarkGroupService.clearUnusedGroup();
|
|
||||||
log.info("PathBookmarkGroupAutoClearTask.clear finish");
|
log.info("PathBookmarkGroupAutoClearTask.clear finish");
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("PathBookmarkGroupAutoClearTask.clear error", e);
|
|
||||||
} finally {
|
|
||||||
lock.unlock();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,9 +48,9 @@
|
|||||||
"defaultValue": "bk_${fileName}_${timestamp}"
|
"defaultValue": "bk_${fileName}_${timestamp}"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "app.exec-log.append-status",
|
"name": "app.exec-log.append-ansi",
|
||||||
"type": "java.lang.Boolean",
|
"type": "java.lang.Boolean",
|
||||||
"description": "是否拼接执行状态.",
|
"description": "是否拼接 ansi 执行状态日志.",
|
||||||
"defaultValue": "true"
|
"defaultValue": "true"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -63,7 +63,7 @@
|
|||||||
"name": "app.exec-log.keep-period",
|
"name": "app.exec-log.keep-period",
|
||||||
"type": "java.lang.Integer",
|
"type": "java.lang.Integer",
|
||||||
"description": "保留周期 (天)",
|
"description": "保留周期 (天)",
|
||||||
"defaultValue": "90"
|
"defaultValue": "60"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,8 @@
|
|||||||
package com.orion.ops.module.infra.task;
|
package com.orion.ops.module.infra.task;
|
||||||
|
|
||||||
|
import com.orion.ops.framework.redis.core.utils.RedisLocks;
|
||||||
import com.orion.ops.module.infra.service.TagService;
|
import com.orion.ops.module.infra.service.TagService;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.redisson.api.RLock;
|
|
||||||
import org.redisson.api.RedissonClient;
|
|
||||||
import org.springframework.scheduling.annotation.Scheduled;
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
@@ -25,34 +24,18 @@ public class TagAutoClearTask {
|
|||||||
*/
|
*/
|
||||||
private static final String LOCK_KEY = "clear:tag:lock";
|
private static final String LOCK_KEY = "clear:tag:lock";
|
||||||
|
|
||||||
@Resource
|
|
||||||
private RedissonClient redissonClient;
|
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private TagService tagService;
|
private TagService tagService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 定时清理未引用的 tag
|
* 清理
|
||||||
*/
|
*/
|
||||||
@Scheduled(cron = "0 0 2 * * ?")
|
@Scheduled(cron = "0 0 2 * * ?")
|
||||||
public void clear() {
|
public void clear() {
|
||||||
log.info("TagAutoClearTask.clear start");
|
log.info("TagAutoClearTask.clear start");
|
||||||
// 获取锁
|
// 获取锁并清理
|
||||||
RLock lock = redissonClient.getLock(LOCK_KEY);
|
RedisLocks.tryLock(LOCK_KEY, tagService::clearUnusedTag);
|
||||||
// 未获取到直接返回
|
|
||||||
if (!lock.tryLock()) {
|
|
||||||
log.info("TagAutoClearTask.clear locked end");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
// 清理
|
|
||||||
tagService.clearUnusedTag();
|
|
||||||
log.info("TagAutoClearTask.clear finish");
|
log.info("TagAutoClearTask.clear finish");
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("TagAutoClearTask.clear error", e);
|
|
||||||
} finally {
|
|
||||||
lock.unlock();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user