You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

108 lines
3.8 KiB

package com.project.ding.utils;
import com.project.ding.domain.dto.UserDTO;
import com.project.ding.domain.entity.SyncLogEntity;
import com.project.ding.domain.entity.UserEntity;
import com.project.ding.domain.service.UserBaseService;
import com.project.ding.mapper.SyncLogMapper;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
@Component
@Slf4j
public class DingUserSyncUtil {
@Resource(name = "dingUserSyncExecutor")
private ExecutorService executor;
@Autowired
private StringRedisTemplate redisTemplate;
@Autowired
private UserBaseService userBaseService;
@Autowired
private DingUtil dingUtil;
@Autowired
private SyncLogMapper syncLogMapper;
private static final String LOCK_KEY = "lock:ding:user_sync";
private static final String LAST_SYNC_KEY = "cache:ding:last_sync_time";
/**
* 触发同步任务
* @param force 是否强制触发(跳过120分钟冷却检查)
*/
public String triggerSync(boolean force) {
// 1. 抢占 Redis 锁(防止多个实例同时跑全量)
Boolean acquired = redisTemplate.opsForValue().setIfAbsent(LOCK_KEY, "true", 1, TimeUnit.HOURS);
if (Boolean.FALSE.equals(acquired)) {
return "同步任务已在运行中,请勿重复触发";
}
// 2. 提交异步任务(不使用 @Async)
CompletableFuture.runAsync(() -> {
try {
// 3. 冷却检查
if (!force) {
String lastSync = redisTemplate.opsForValue().get(LAST_SYNC_KEY);
if (lastSync != null && (System.currentTimeMillis() - Long.parseLong(lastSync) < 120 * 60 * 1000)) {
log.info("处于冷却期,跳过全量同步");
return;
}
}
log.info(">>> 开始钉钉用户全量同步 (force={})", force);
runActualSyncTask();
} catch (Exception e) {
log.error("全量同步发生严重异常", e);
} finally {
// 4. 释放锁
redisTemplate.delete(LOCK_KEY);
}
}, executor);
return "同步任务已启动,请查看系统日志或更新时间";
}
private void runActualSyncTask() {
// 插入一条同步日志
SyncLogEntity syncLogEntity = new SyncLogEntity();
syncLogEntity.setStartTime(new Date());
syncLogEntity.setStatus(0);
syncLogMapper.insert(syncLogEntity);
// 开始同步
try {
List<UserDTO> allUserDTOList = dingUtil.getAllUserDTO();
userBaseService.saveOrUpdateBatch(allUserDTOList.stream()
.map(dto -> dto.toEntity(UserEntity::new))
.collect(Collectors.toList()) , 300);
syncLogEntity.setStatus(1);
syncLogEntity.setEndTime(new Date());
syncLogMapper.updateById(syncLogEntity);
redisTemplate.opsForValue().set(LAST_SYNC_KEY, String.valueOf(System.currentTimeMillis()));
log.info(">>> 全量同步完成");
} catch (Exception e) {
// 同步失败更新
syncLogEntity.setEndTime(new Date());
syncLogEntity.setStatus(2); // 失败
syncLogEntity.setErrorMsg(e.getMessage());
syncLogMapper.updateById(syncLogEntity);
log.error(">>> 全量同步过程报错", e);
}
}
}