package com.fdkankan.scene.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.fdkankan.common.constant.CommonStatus;
import com.fdkankan.common.util.FileUtils;
import com.fdkankan.model.utils.CreateObjUtil;
import com.fdkankan.redis.constant.RedisKey;
import com.fdkankan.redis.constant.RedisLockKey;
import com.fdkankan.redis.util.RedisLockUtil;
import com.fdkankan.redis.util.RedisUtil;
import com.fdkankan.scene.bean.SceneBean;
import com.fdkankan.scene.entity.SceneClean;
import com.fdkankan.scene.mapper.ISceneCleanMapper;
import com.fdkankan.scene.service.ISceneCleanService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import java.util.Calendar;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
/**
*
* 服务实现类
*
*
* @author
* @since 2022-10-09
*/
@RefreshScope
@Service
public class SceneCleanServiceImpl extends ServiceImpl implements ISceneCleanService {
@Autowired
private RedisLockUtil redisLockUtil;
@Autowired
private RedisUtil redisUtil;
@Value("${scene.clean.size:10}")
private Integer sceneCleanSize;
@Transactional
@Override
public void sceneCleanResource(){
//这里考虑到日后会集群部署,所以查询需要清理资源的场景的写法是负载均衡写法,为了避免幻读影响到查询结果,所以写库放在循环外层
List allInsertList = Lists.newArrayList();
Set allUpdateSet = Sets.newHashSet();
DateTime dateTime = DateUtil.beginOfDay(DateUtil.offsetMonth(Calendar.getInstance().getTime(), -6));
while (true){
String uuid = UUID.randomUUID().toString();
boolean lock = redisLockUtil.lock(RedisLockKey.LOCK_SCENE_CLEAN, uuid, RedisKey.EXPIRE_TIME_1_MINUTE);
if(!lock){
try {
Thread.sleep(RandomUtil.randomLong(1000L, 2000L));
continue;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
long index = 0;
String indexStr = redisUtil.get(RedisKey.SCENE_CLEAN_INDEX);
if(StringUtils.isNotBlank(indexStr)){
index = Long.valueOf(indexStr);
}
//下标增加1000
redisUtil.incr(RedisKey.SCENE_CLEAN_INDEX, sceneCleanSize);
//解锁
redisLockUtil.unlockLua(RedisLockKey.LOCK_SCENE_CLEAN, uuid);
//查询需要清理资源的场景
List sceneBeanList = this.selectNeadCleanScene(index, sceneCleanSize, dateTime);
//如果查出来的场景集合是空,证明已经没有场景资源需要删除,则需要把查询下表删除,等待下一次定时任务执行
if(CollectionUtils.isEmpty(sceneBeanList)){
redisUtil.del(RedisKey.SCENE_CLEAN_INDEX);
break;
}
List insertList = Lists.newArrayList();
List numList = sceneBeanList.stream().map(scene -> scene.getNum()).collect(Collectors.toList());
List updateList = this.list(new LambdaQueryWrapper().in(SceneClean::getNum, numList));
Set updateSet = new HashSet<>();
if(!CollectionUtils.isEmpty(updateList)){
updateList.stream().forEach(item->{
updateSet.add(item.getNum());
});
}
sceneBeanList.stream().forEach(scene -> {
if(StringUtils.isNotBlank(scene.getDataSource())){
try {
CreateObjUtil.deleteFile(scene.getDataSource());
} catch (Exception e) {
e.printStackTrace();
}
}
if(!updateSet.contains(scene.getNum())){
SceneClean sceneClean = new SceneClean();
sceneClean.setNum(scene.getNum());
insertList.add(sceneClean);
}
});
if(!CollectionUtils.isEmpty(insertList)){
allInsertList.addAll(insertList);
}
if(!CollectionUtils.isEmpty(updateSet)){
allUpdateSet.addAll(updateSet);
}
}
//写库
if(CollUtil.isNotEmpty(allInsertList)){
this.saveBatch(allInsertList);
}
if(CollUtil.isNotEmpty(allUpdateSet)){
this.update(new LambdaUpdateWrapper().set(SceneClean::getState,
CommonStatus.YES.code()).in(SceneClean::getNum, allUpdateSet));
}
}
@Override
public List selectNeadCleanScene(long index, int size, Date time) {
return this.baseMapper.selectNeadCleanScene(index, size, time);
}
}