You've already forked FrameTour-BE
refactor(video): 移除设备视频连续性检查定时任务
- 删除了 DeviceVideoContinuityCheckTask 定时任务类 - 从 DeviceVideoContinuityController 中移除手动检查接口 - 从生产环境日志配置中移除相关日志记录器配置 - 移除了 RedisTemplate 和 ObjectMapper 的依赖注入 - 移除了设备视频连续性检查相关的定时任务逻辑 - 移除了手动触发检查的 API 接口实现
This commit is contained in:
@@ -6,7 +6,6 @@ import com.ycwl.basic.device.entity.common.DeviceVideoContinuityCache;
|
||||
import com.ycwl.basic.model.pc.device.entity.DeviceEntity;
|
||||
import com.ycwl.basic.model.pc.device.req.VideoContinuityReportReq;
|
||||
import com.ycwl.basic.repository.DeviceRepository;
|
||||
import com.ycwl.basic.task.DeviceVideoContinuityCheckTask;
|
||||
import com.ycwl.basic.utils.ApiResponse;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -37,7 +36,6 @@ public class DeviceVideoContinuityController {
|
||||
|
||||
private final RedisTemplate<String, String> redisTemplate;
|
||||
private final ObjectMapper objectMapper;
|
||||
private final DeviceVideoContinuityCheckTask checkTask;
|
||||
private final DeviceRepository deviceRepository;
|
||||
|
||||
/**
|
||||
@@ -78,15 +76,7 @@ public class DeviceVideoContinuityController {
|
||||
@PostMapping("/{deviceId}/check")
|
||||
public ApiResponse<DeviceVideoContinuityCache> manualCheck(@PathVariable Long deviceId) {
|
||||
log.info("手动触发设备 {} 的视频连续性检查", deviceId);
|
||||
|
||||
try {
|
||||
DeviceVideoContinuityCache result = checkTask.manualCheck(deviceId);
|
||||
return ApiResponse.success(result);
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("手动检查设备 {} 视频连续性失败", deviceId, e);
|
||||
return ApiResponse.buildResponse(500, null, "检查失败: " + e.getMessage());
|
||||
}
|
||||
return ApiResponse.success(null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,226 +0,0 @@
|
||||
package com.ycwl.basic.task;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.ycwl.basic.device.DeviceFactory;
|
||||
import com.ycwl.basic.device.entity.common.DeviceVideoContinuityCache;
|
||||
import com.ycwl.basic.device.entity.common.VideoContinuityResult;
|
||||
import com.ycwl.basic.device.operator.IDeviceStorageOperator;
|
||||
import com.ycwl.basic.integration.common.response.PageResponse;
|
||||
import com.ycwl.basic.integration.device.dto.device.DeviceV2DTO;
|
||||
import com.ycwl.basic.integration.device.service.DeviceIntegrationService;
|
||||
import com.ycwl.basic.model.pc.device.entity.DeviceConfigEntity;
|
||||
import com.ycwl.basic.repository.DeviceRepository;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Profile;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* 设备视频连续性检查定时任务
|
||||
* - 仅在生产环境(prod)运行
|
||||
* - 每5分钟执行一次
|
||||
* - 检查前12分钟到前2分钟的视频连续性
|
||||
* - 仅在9点到18点之间检查
|
||||
* - 结果缓存到Redis中
|
||||
*
|
||||
* @author Claude Code
|
||||
* @date 2025-09-01
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
@EnableScheduling
|
||||
//@Profile("prod")
|
||||
public class DeviceVideoContinuityCheckTask {
|
||||
|
||||
private static final String REDIS_KEY_PREFIX = "device:video:continuity:";
|
||||
private static final int CACHE_TTL_HOURS = 24; // 缓存24小时
|
||||
private static final int START_HOUR = 9; // 开始检查时间 9:00
|
||||
private static final int END_HOUR = 18; // 结束检查时间 18:00
|
||||
|
||||
@Autowired
|
||||
private DeviceIntegrationService deviceIntegrationService;
|
||||
|
||||
@Autowired
|
||||
private DeviceRepository deviceRepository;
|
||||
|
||||
@Autowired
|
||||
private RedisTemplate<String, String> redisTemplate;
|
||||
|
||||
@Autowired
|
||||
private ObjectMapper objectMapper;
|
||||
|
||||
/**
|
||||
* 定时任务:每5分钟执行一次
|
||||
* cron表达式: 0 0/5 * * * * 表示每5分钟执行一次
|
||||
*/
|
||||
@Scheduled(cron = "0 0/5 * * * *")
|
||||
public void checkDeviceVideoContinuity() {
|
||||
// 检查是否在执行时间范围内(9:00-18:00)
|
||||
int currentHour = Calendar.getInstance().get(Calendar.HOUR_OF_DAY);
|
||||
if (currentHour < START_HOUR || currentHour >= END_HOUR) {
|
||||
log.debug("当前时间 {}:00 不在检查时间范围内({}:00-{}:00),跳过检查",
|
||||
currentHour, START_HOUR, END_HOUR);
|
||||
return;
|
||||
}
|
||||
|
||||
log.info("开始执行设备视频连续性检查定时任务");
|
||||
long startTime = System.currentTimeMillis();
|
||||
|
||||
try {
|
||||
// 获取所有激活的设备(分页获取,每次100个)
|
||||
int pageSize = 100;
|
||||
int currentPage = 1;
|
||||
int totalChecked = 0;
|
||||
int successCount = 0;
|
||||
int failureCount = 0;
|
||||
|
||||
while (true) {
|
||||
PageResponse<DeviceV2DTO> pageResponse = deviceIntegrationService.listDevices(
|
||||
currentPage, pageSize, null, null, null, 1, null, null
|
||||
);
|
||||
|
||||
if (pageResponse == null || pageResponse.getList() == null
|
||||
|| pageResponse.getList().isEmpty()) {
|
||||
break;
|
||||
}
|
||||
|
||||
// 检查每个设备的视频连续性
|
||||
for (DeviceV2DTO device : pageResponse.getList()) {
|
||||
try {
|
||||
boolean checked = checkSingleDevice(device);
|
||||
totalChecked++;
|
||||
if (checked) {
|
||||
successCount++;
|
||||
} else {
|
||||
failureCount++;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("检查设备 {} 视频连续性失败: {}", device.getId(), e.getMessage(), e);
|
||||
failureCount++;
|
||||
totalChecked++;
|
||||
}
|
||||
}
|
||||
|
||||
// 检查是否还有更多页
|
||||
int totalPages = (int) Math.ceil((double) pageResponse.getTotal() / pageSize);
|
||||
if (currentPage >= totalPages) {
|
||||
break;
|
||||
}
|
||||
currentPage++;
|
||||
}
|
||||
|
||||
long endTime = System.currentTimeMillis();
|
||||
log.info("设备视频连续性检查任务完成: 总计检查 {} 个设备, 成功 {}, 失败 {}, 耗时 {}ms",
|
||||
totalChecked, successCount, failureCount, (endTime - startTime));
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("执行设备视频连续性检查定时任务失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查单个设备的视频连续性
|
||||
*
|
||||
* @param device 设备信息
|
||||
* @return true表示检查成功并缓存,false表示跳过检查
|
||||
*/
|
||||
private boolean checkSingleDevice(DeviceV2DTO device) {
|
||||
try {
|
||||
// 获取设备配置
|
||||
DeviceConfigEntity config = deviceRepository.getDeviceConfig(device.getId());
|
||||
if (config == null) {
|
||||
log.debug("设备 {} 没有配置信息,跳过检查", device.getId());
|
||||
return false;
|
||||
}
|
||||
|
||||
// 获取设备的存储操作器
|
||||
IDeviceStorageOperator operator = DeviceFactory.getDeviceStorageOperator(device, config);
|
||||
if (operator == null) {
|
||||
log.debug("设备 {} 没有配置存储操作器,跳过检查", device.getId());
|
||||
return false;
|
||||
}
|
||||
|
||||
// 计算检查时间范围: 当前时间向前12分钟到向前2分钟
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.add(Calendar.MINUTE, -2);
|
||||
Date endDate = calendar.getTime();
|
||||
|
||||
calendar.add(Calendar.MINUTE, -10); // 再向前10分钟,总共12分钟
|
||||
Date startDate = calendar.getTime();
|
||||
|
||||
// 执行连续性检查(允许2秒间隙)
|
||||
VideoContinuityResult result = operator.checkVideoContinuity(startDate, endDate, 2000L);
|
||||
|
||||
// 如果设备不支持连续性检查,检查是否已有外部上报的缓存记录
|
||||
String redisKey = REDIS_KEY_PREFIX + device.getId();
|
||||
if (!result.isSupport()) {
|
||||
String existingCache = redisTemplate.opsForValue().get(redisKey);
|
||||
if (existingCache != null) {
|
||||
// 已有缓存记录(可能是外部工具上报的),不覆盖
|
||||
log.debug("设备 {} 不支持内部连续性检查,但已有缓存记录,跳过覆盖", device.getId());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 创建缓存对象
|
||||
DeviceVideoContinuityCache cache = DeviceVideoContinuityCache.fromResult(
|
||||
device.getId(), result, startDate, endDate
|
||||
);
|
||||
|
||||
// 存储到Redis
|
||||
String cacheJson = objectMapper.writeValueAsString(cache);
|
||||
redisTemplate.opsForValue().set(redisKey, cacheJson, CACHE_TTL_HOURS, TimeUnit.HOURS);
|
||||
|
||||
log.info("设备 {} 视频连续性检查完成: support={}, continuous={}, videos={}, gaps={}, duration={}ms",
|
||||
device.getId(), result.isSupport(), result.isContinuous(),
|
||||
result.getTotalVideos(), result.getGapCount(), result.getTotalDurationMs());
|
||||
|
||||
return true;
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("检查设备 {} 视频连续性失败", device.getId(), e);
|
||||
throw new RuntimeException("检查设备视频连续性失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 手动触发检查(用于测试)
|
||||
*
|
||||
* @param deviceId 设备ID
|
||||
* @return 检查结果
|
||||
*/
|
||||
public DeviceVideoContinuityCache manualCheck(Long deviceId) {
|
||||
log.info("手动触发设备 {} 的视频连续性检查", deviceId);
|
||||
|
||||
try {
|
||||
// 获取设备信息
|
||||
DeviceV2DTO device = deviceIntegrationService.getDevice(deviceId);
|
||||
if (device == null) {
|
||||
throw new RuntimeException("设备不存在: " + deviceId);
|
||||
}
|
||||
|
||||
// 检查设备
|
||||
checkSingleDevice(device);
|
||||
|
||||
// 从Redis获取结果
|
||||
String redisKey = REDIS_KEY_PREFIX + deviceId;
|
||||
String cacheJson = redisTemplate.opsForValue().get(redisKey);
|
||||
if (cacheJson == null) {
|
||||
throw new RuntimeException("检查完成但未找到缓存结果");
|
||||
}
|
||||
|
||||
return objectMapper.readValue(cacheJson, DeviceVideoContinuityCache.class);
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("手动检查设备 {} 视频连续性失败", deviceId, e);
|
||||
throw new RuntimeException("手动检查失败: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -98,10 +98,6 @@
|
||||
<appender-ref ref="DEVICE_STORAGE_OPERATOR_LOG"/>
|
||||
</logger>
|
||||
|
||||
<logger name="com.ycwl.basic.task.DeviceVideoContinuityCheckTask" level="INFO" additivity="false">
|
||||
<appender-ref ref="TASK_LOG"/>
|
||||
</logger>
|
||||
|
||||
<logger name="com.ycwl.basic.task.FaceCleaner" level="INFO" additivity="false">
|
||||
<appender-ref ref="TASK_LOG"/>
|
||||
</logger>
|
||||
|
||||
Reference in New Issue
Block a user