1.48
修改总结 新增文件 SyncLockType.java - 同步锁类型枚举,定义了 JENKINS_SYNC、GITLAB_SYNC、K8S_SYNC 三种锁类型 修改文件 文件 修改内容 SyncLockManager.java 新增 tryLock(SyncLockType, Object...) 和 unlock(SyncLockType, Object...) 方法,支持显式指定锁类型 JenkinsViewServiceImpl.java syncViews 改用 SyncLockType.JENKINS_SYNC JenkinsJobServiceImpl.java syncJobs 两个重载方法都改用 SyncLockType.JENKINS_SYNC,锁粒度统一为 externalSystemId JenkinsBuildServiceImpl.java syncBuilds 改用 SyncLockType.JENKINS_SYNC
This commit is contained in:
parent
c82bb937d1
commit
9f3353e54a
@ -7,13 +7,16 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 智能同步任务本地锁管理器
|
* 智能同步任务本地锁管理器
|
||||||
* <p>自动识别调用者(类名+方法名)和参数,生成唯一锁key,无需手动指定锁类型</p>
|
* <p>支持两种使用方式:</p>
|
||||||
|
* <ol>
|
||||||
|
* <li>自动识别调用者(类名+方法名)生成锁key - 适用于单方法独立锁</li>
|
||||||
|
* <li>显式指定锁类型 - 适用于跨方法/跨服务协调锁</li>
|
||||||
|
* </ol>
|
||||||
*
|
*
|
||||||
* <p>使用示例:
|
* <p>使用示例1(自动识别):
|
||||||
* <pre>
|
* <pre>
|
||||||
* // 加锁(自动识别调用方法和参数)
|
|
||||||
* if (!syncLockManager.tryLock(externalSystemId)) {
|
* if (!syncLockManager.tryLock(externalSystemId)) {
|
||||||
* return; // 已有同步任务在执行
|
* return;
|
||||||
* }
|
* }
|
||||||
* try {
|
* try {
|
||||||
* // 执行同步逻辑
|
* // 执行同步逻辑
|
||||||
@ -22,17 +25,91 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||||||
* }
|
* }
|
||||||
* </pre>
|
* </pre>
|
||||||
*
|
*
|
||||||
* <p>锁key格式:ClassName.methodName:param1:param2:...</p>
|
* <p>使用示例2(显式锁类型 - 推荐用于跨服务协调):
|
||||||
|
* <pre>
|
||||||
|
* if (!syncLockManager.tryLock(SyncLockType.JENKINS_SYNC, externalSystemId)) {
|
||||||
|
* return;
|
||||||
|
* }
|
||||||
|
* try {
|
||||||
|
* // 执行同步逻辑
|
||||||
|
* } finally {
|
||||||
|
* syncLockManager.unlock(SyncLockType.JENKINS_SYNC, externalSystemId);
|
||||||
|
* }
|
||||||
|
* </pre>
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Component
|
@Component
|
||||||
public class SyncLockManager {
|
public class SyncLockManager {
|
||||||
|
|
||||||
// 统一的锁存储:key = ClassName.methodName:param1:param2:...
|
// 统一的锁存储
|
||||||
private final ConcurrentHashMap<String, Boolean> locks = new ConcurrentHashMap<>();
|
private final ConcurrentHashMap<String, Boolean> locks = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
// ==================== 显式锁类型方法(推荐用于跨服务协调) ====================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 尝试获取锁(显式指定锁类型)
|
||||||
|
* <p>推荐用于需要跨方法/跨服务协调的场景</p>
|
||||||
|
*
|
||||||
|
* @param lockType 锁类型
|
||||||
|
* @param params 锁参数(如 externalSystemId)
|
||||||
|
* @return true-获取成功,false-已被锁定
|
||||||
|
*/
|
||||||
|
public boolean tryLock(SyncLockType lockType, Object... params) {
|
||||||
|
String lockKey = buildLockKey(lockType, params);
|
||||||
|
boolean acquired = locks.putIfAbsent(lockKey, true) == null;
|
||||||
|
|
||||||
|
if (!acquired) {
|
||||||
|
log.warn("同步任务正在执行中,跳过本次同步: lockType={}, params={}",
|
||||||
|
lockType.getKey(), formatParams(params));
|
||||||
|
} else {
|
||||||
|
log.debug("获取同步锁成功: lockType={}, params={}",
|
||||||
|
lockType.getKey(), formatParams(params));
|
||||||
|
}
|
||||||
|
|
||||||
|
return acquired;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 释放锁(显式指定锁类型)
|
||||||
|
*
|
||||||
|
* @param lockType 锁类型
|
||||||
|
* @param params 锁参数(必须与tryLock时完全一致)
|
||||||
|
*/
|
||||||
|
public void unlock(SyncLockType lockType, Object... params) {
|
||||||
|
String lockKey = buildLockKey(lockType, params);
|
||||||
|
locks.remove(lockKey);
|
||||||
|
log.debug("同步任务完成,释放锁: lockType={}, params={}",
|
||||||
|
lockType.getKey(), formatParams(params));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查锁是否被持有(显式指定锁类型)
|
||||||
|
*
|
||||||
|
* @param lockType 锁类型
|
||||||
|
* @param params 锁参数
|
||||||
|
* @return true-已被锁定,false-未锁定
|
||||||
|
*/
|
||||||
|
public boolean isLocked(SyncLockType lockType, Object... params) {
|
||||||
|
String lockKey = buildLockKey(lockType, params);
|
||||||
|
return locks.containsKey(lockKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构建锁key(显式锁类型)
|
||||||
|
*/
|
||||||
|
private String buildLockKey(SyncLockType lockType, Object... params) {
|
||||||
|
StringBuilder key = new StringBuilder(lockType.getKey());
|
||||||
|
for (Object param : params) {
|
||||||
|
key.append(":").append(param != null ? param : "null");
|
||||||
|
}
|
||||||
|
return key.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 自动识别调用者方法(向后兼容) ====================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 尝试获取锁(自动识别调用者)
|
* 尝试获取锁(自动识别调用者)
|
||||||
|
* <p>适用于单方法独立锁场景,不需要跨服务协调</p>
|
||||||
*
|
*
|
||||||
* @param params 锁参数(如 externalSystemId, viewId等)
|
* @param params 锁参数(如 externalSystemId, viewId等)
|
||||||
* @return true-获取成功,false-已被锁定
|
* @return true-获取成功,false-已被锁定
|
||||||
|
|||||||
@ -25,6 +25,7 @@ import com.qqchen.deploy.backend.notification.service.INotificationSendService;
|
|||||||
import com.qqchen.deploy.backend.notification.dto.SendNotificationRequest;
|
import com.qqchen.deploy.backend.notification.dto.SendNotificationRequest;
|
||||||
import com.qqchen.deploy.backend.deploy.dto.sync.JenkinsSyncContext;
|
import com.qqchen.deploy.backend.deploy.dto.sync.JenkinsSyncContext;
|
||||||
import com.qqchen.deploy.backend.deploy.lock.SyncLockManager;
|
import com.qqchen.deploy.backend.deploy.lock.SyncLockManager;
|
||||||
|
import com.qqchen.deploy.backend.deploy.lock.SyncLockType;
|
||||||
import com.qqchen.deploy.backend.framework.enums.ResponseCode;
|
import com.qqchen.deploy.backend.framework.enums.ResponseCode;
|
||||||
import com.qqchen.deploy.backend.framework.exception.BusinessException;
|
import com.qqchen.deploy.backend.framework.exception.BusinessException;
|
||||||
import com.qqchen.deploy.backend.framework.service.impl.BaseServiceImpl;
|
import com.qqchen.deploy.backend.framework.service.impl.BaseServiceImpl;
|
||||||
@ -117,8 +118,8 @@ public class JenkinsBuildServiceImpl extends BaseServiceImpl<JenkinsBuild, Jenki
|
|||||||
@Async
|
@Async
|
||||||
@Transactional
|
@Transactional
|
||||||
public void syncBuilds(Long externalSystemId) {
|
public void syncBuilds(Long externalSystemId) {
|
||||||
// 尝试获取锁(自动识别调用者:JenkinsBuildServiceImpl.syncBuilds)
|
// 尝试获取锁(使用统一的 JENKINS_SYNC 锁类型,与 syncViews、syncJobs 共享锁)
|
||||||
if (!syncLockManager.tryLock(externalSystemId)) {
|
if (!syncLockManager.tryLock(SyncLockType.JENKINS_SYNC, externalSystemId)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,7 +130,7 @@ public class JenkinsBuildServiceImpl extends BaseServiceImpl<JenkinsBuild, Jenki
|
|||||||
checkBuildNotifications(externalSystemId);
|
checkBuildNotifications(externalSystemId);
|
||||||
} finally {
|
} finally {
|
||||||
// 释放锁
|
// 释放锁
|
||||||
syncLockManager.unlock(externalSystemId);
|
syncLockManager.unlock(SyncLockType.JENKINS_SYNC, externalSystemId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -20,6 +20,7 @@ import com.qqchen.deploy.backend.deploy.service.IJenkinsSyncHistoryService;
|
|||||||
import com.qqchen.deploy.backend.framework.enums.ResponseCode;
|
import com.qqchen.deploy.backend.framework.enums.ResponseCode;
|
||||||
import com.qqchen.deploy.backend.framework.exception.BusinessException;
|
import com.qqchen.deploy.backend.framework.exception.BusinessException;
|
||||||
import com.qqchen.deploy.backend.framework.service.impl.BaseServiceImpl;
|
import com.qqchen.deploy.backend.framework.service.impl.BaseServiceImpl;
|
||||||
|
import com.qqchen.deploy.backend.deploy.lock.SyncLockType;
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.scheduling.annotation.Async;
|
import org.springframework.scheduling.annotation.Async;
|
||||||
@ -74,15 +75,15 @@ public class JenkinsJobServiceImpl extends BaseServiceImpl<JenkinsJob, JenkinsJo
|
|||||||
@Async
|
@Async
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public void syncJobs(Long externalSystemId) {
|
public void syncJobs(Long externalSystemId) {
|
||||||
// 尝试获取锁(只使用 externalSystemId 作为锁参数)
|
// 尝试获取锁(使用统一的 JENKINS_SYNC 锁类型,与 syncViews、syncBuilds 共享锁)
|
||||||
if (!syncLockManager.tryLock(externalSystemId)) {
|
if (!syncLockManager.tryLock(SyncLockType.JENKINS_SYNC, externalSystemId)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
doSyncJobs(externalSystemId, null);
|
doSyncJobs(externalSystemId, null);
|
||||||
} finally {
|
} finally {
|
||||||
syncLockManager.unlock(externalSystemId);
|
syncLockManager.unlock(SyncLockType.JENKINS_SYNC, externalSystemId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,15 +97,15 @@ public class JenkinsJobServiceImpl extends BaseServiceImpl<JenkinsJob, JenkinsJo
|
|||||||
@Async
|
@Async
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public void syncJobs(Long externalSystemId, Long viewId) {
|
public void syncJobs(Long externalSystemId, Long viewId) {
|
||||||
// 尝试获取锁(使用 externalSystemId 和 viewId 作为锁参数)
|
// 尝试获取锁(使用统一的 JENKINS_SYNC 锁类型,锁粒度为 externalSystemId,忽略 viewId)
|
||||||
if (!syncLockManager.tryLock(externalSystemId, viewId)) {
|
if (!syncLockManager.tryLock(SyncLockType.JENKINS_SYNC, externalSystemId)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
doSyncJobs(externalSystemId, viewId);
|
doSyncJobs(externalSystemId, viewId);
|
||||||
} finally {
|
} finally {
|
||||||
syncLockManager.unlock(externalSystemId, viewId);
|
syncLockManager.unlock(SyncLockType.JENKINS_SYNC, externalSystemId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -18,6 +18,7 @@ import com.qqchen.deploy.backend.deploy.service.IJenkinsViewService;
|
|||||||
import com.qqchen.deploy.backend.framework.enums.ResponseCode;
|
import com.qqchen.deploy.backend.framework.enums.ResponseCode;
|
||||||
import com.qqchen.deploy.backend.framework.exception.BusinessException;
|
import com.qqchen.deploy.backend.framework.exception.BusinessException;
|
||||||
import com.qqchen.deploy.backend.framework.service.impl.BaseServiceImpl;
|
import com.qqchen.deploy.backend.framework.service.impl.BaseServiceImpl;
|
||||||
|
import com.qqchen.deploy.backend.deploy.lock.SyncLockType;
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.scheduling.annotation.Async;
|
import org.springframework.scheduling.annotation.Async;
|
||||||
@ -72,15 +73,15 @@ public class JenkinsViewServiceImpl extends BaseServiceImpl<JenkinsView, Jenkins
|
|||||||
@Async
|
@Async
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public void syncViews(Long externalSystemId) {
|
public void syncViews(Long externalSystemId) {
|
||||||
// 尝试获取锁
|
// 尝试获取锁(使用统一的 JENKINS_SYNC 锁类型,与 syncJobs、syncBuilds 共享锁)
|
||||||
if (!syncLockManager.tryLock(externalSystemId)) {
|
if (!syncLockManager.tryLock(SyncLockType.JENKINS_SYNC, externalSystemId)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
doSyncViews(externalSystemId);
|
doSyncViews(externalSystemId);
|
||||||
} finally {
|
} finally {
|
||||||
syncLockManager.unlock(externalSystemId);
|
syncLockManager.unlock(SyncLockType.JENKINS_SYNC, externalSystemId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user