feat: 优化
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
package cn.iocoder.yudao.module.tik.media;
|
||||
|
||||
import cn.iocoder.yudao.module.infra.api.file.FileApi;
|
||||
import cn.iocoder.yudao.module.tik.mix.config.IceProperties;
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
@@ -34,6 +35,7 @@ import java.util.*;
|
||||
public class BatchProduceAlignment {
|
||||
|
||||
private final IceProperties properties;
|
||||
private final FileApi fileApi;
|
||||
private Client iceClient;
|
||||
|
||||
public void initClient() throws Exception {
|
||||
@@ -105,8 +107,9 @@ public class BatchProduceAlignment {
|
||||
initClient();
|
||||
}
|
||||
|
||||
// 纯画面模式:仅拼接视频片段,添加空的音频轨道
|
||||
// 纯画面模式:仅拼接视频片段,为每个视频添加静音音频轨道
|
||||
JSONArray videoClipArray = new JSONArray();
|
||||
JSONArray audioClipArray = new JSONArray();
|
||||
|
||||
// 按顺序拼接视频片段(不随机打乱)
|
||||
for (int i = 0; i < videoArray.length; i++) {
|
||||
@@ -120,21 +123,39 @@ public class BatchProduceAlignment {
|
||||
}
|
||||
|
||||
log.debug("[ICE][添加视频片段][{}: {}]", i + 1, videoUrl);
|
||||
// 每个视频片段添加静音效果(Volume: 0)
|
||||
String videoClip = "{\"MediaURL\":\""+videoUrl+"\",\"ReferenceClipId\":\""+clipId+"\",\"Volume\":0,\"Effects\":[{\"Type\":\"Background\",\"SubType\":\"Blur\",\"Radius\":0.1}]}";
|
||||
// 使用标准的 MediaURL 参数(符合 ICE API 文档规范)
|
||||
String videoClip = "{\"MediaURL\":\"" + videoUrl + "\"}";
|
||||
videoClipArray.add(JSONObject.parseObject(videoClip));
|
||||
|
||||
// 为每个视频片段添加静音的音频轨道
|
||||
JSONObject audioClip = new JSONObject();
|
||||
audioClip.put("MediaURL", videoUrl);
|
||||
// 添加静音效果
|
||||
JSONObject volumeEffect = new JSONObject();
|
||||
volumeEffect.put("Type", "Volume");
|
||||
volumeEffect.put("Gain", 0); // 0 表示静音
|
||||
JSONArray effects = new JSONArray();
|
||||
effects.add(volumeEffect);
|
||||
audioClip.put("Effects", effects);
|
||||
audioClipArray.add(audioClip);
|
||||
}
|
||||
|
||||
// 添加空的音频轨道(避免ICE报错)
|
||||
JSONArray emptyAudioClipArray = new JSONArray();
|
||||
String timeline = "{\"VideoTracks\":[{\"VideoTrackClips\":"+videoClipArray.toJSONString()+"}],\"AudioTracks\":[{\"AudioTrackClips\":"+emptyAudioClipArray.toJSONString()+"}]}";
|
||||
// 构建时间线,包含视频轨道和音频轨道
|
||||
String timeline = "{\"VideoTracks\":[{\"VideoTrackClips\":"+videoClipArray.toJSONString()+"}],\"AudioTracks\":[{\"AudioTrackClips\":"+audioClipArray.toJSONString()+"}]}";
|
||||
|
||||
//
|
||||
String targetFileName = UUID.randomUUID().toString().replace("-", "");
|
||||
String outputMediaUrl = "http://" + properties.getBucket() + ".oss-" + properties.getRegionId() + ".aliyuncs.com/ice_output/" + targetFileName + ".mp4";
|
||||
String bucketEndpoint = "https://" + properties.getBucket() + ".oss-" + properties.getRegionId() + ".aliyuncs.com";
|
||||
String outputMediaPath = "/ice_output/" + targetFileName + ".mp4";
|
||||
String outputMediaUrl = bucketEndpoint + outputMediaPath;
|
||||
|
||||
// 生成签名URL(有效期24小时)使用公共API
|
||||
String signedUrl = fileApi.presignGetUrl(outputMediaUrl, 24 * 3600);
|
||||
|
||||
int width = 720;
|
||||
int height = 1280;
|
||||
String outputMediaConfig = "{\"MediaURL\":\"" + outputMediaUrl + "\",\"Width\":"+width+",\"Height\":"+height+"}";
|
||||
int bitrate = 2000; // 输出码率 2000 Kbit/s(符合 ICE API 文档推荐)
|
||||
String outputMediaConfig = "{\"MediaURL\":\"" + signedUrl + "\",\"Width\":" + width + ",\"Height\":" + height + ",\"Bitrate\":" + bitrate + "}";
|
||||
|
||||
SubmitMediaProducingJobRequest request = new SubmitMediaProducingJobRequest();
|
||||
request.setTimeline(timeline);
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
package cn.iocoder.yudao.module.tik.mix.config;
|
||||
|
||||
import org.springframework.boot.CommandLineRunner;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 混剪任务设计优化
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Component
|
||||
public class MixTaskDataOptimization implements CommandLineRunner {
|
||||
|
||||
@Override
|
||||
public void run(String... args) throws Exception {
|
||||
// 统一通过 setOutputUrlList/getOutputUrlList 方法访问
|
||||
// 禁止直接操作 outputUrls 字段
|
||||
// 设计原则:封装优于修复
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,7 @@
|
||||
package cn.iocoder.yudao.module.tik.mix.dal.dataobject;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
|
||||
import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
@@ -43,13 +41,13 @@ public class MixTaskDO extends TenantBaseDO {
|
||||
private String text;
|
||||
|
||||
/**
|
||||
* 视频素材URL列表(JSON)
|
||||
* 视频素材URL列表(逗号分隔)
|
||||
*/
|
||||
@TableField("video_urls")
|
||||
private String videoUrls;
|
||||
|
||||
/**
|
||||
* 背景音乐URL列表(JSON)
|
||||
* 背景音乐URL列表(逗号分隔)
|
||||
*/
|
||||
@TableField("bg_music_urls")
|
||||
private String bgMusicUrls;
|
||||
@@ -61,13 +59,13 @@ public class MixTaskDO extends TenantBaseDO {
|
||||
private Integer produceCount;
|
||||
|
||||
/**
|
||||
* 任务ID列表(JSON)
|
||||
* 任务ID列表(逗号分隔)
|
||||
*/
|
||||
@TableField("job_ids")
|
||||
private String jobIds;
|
||||
|
||||
/**
|
||||
* 输出文件URL列表(JSON)
|
||||
* 输出文件URL列表(逗号分隔)
|
||||
*/
|
||||
@TableField("output_urls")
|
||||
private String outputUrls;
|
||||
@@ -101,55 +99,67 @@ public class MixTaskDO extends TenantBaseDO {
|
||||
* 获取视频URL列表
|
||||
*/
|
||||
public List<String> getVideoUrlList() {
|
||||
return JsonUtils.parseObject(videoUrls, new TypeReference<List<String>>() {});
|
||||
if (videoUrls == null || videoUrls.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
return List.of(videoUrls.split(","));
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置视频URL列表
|
||||
*/
|
||||
public void setVideoUrlList(List<String> videoUrls) {
|
||||
this.videoUrls = JsonUtils.toJsonString(videoUrls);
|
||||
this.videoUrls = videoUrls == null || videoUrls.isEmpty() ? null : String.join(",", videoUrls);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取背景音乐URL列表
|
||||
*/
|
||||
public List<String> getBgMusicUrlList() {
|
||||
return JsonUtils.parseObject(bgMusicUrls, new TypeReference<List<String>>() {});
|
||||
if (bgMusicUrls == null || bgMusicUrls.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
return List.of(bgMusicUrls.split(","));
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置背景音乐URL列表
|
||||
*/
|
||||
public void setBgMusicUrlList(List<String> bgMusicUrls) {
|
||||
this.bgMusicUrls = JsonUtils.toJsonString(bgMusicUrls);
|
||||
this.bgMusicUrls = bgMusicUrls == null || bgMusicUrls.isEmpty() ? null : String.join(",", bgMusicUrls);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取任务ID列表
|
||||
*/
|
||||
public List<String> getJobIdList() {
|
||||
return JsonUtils.parseObject(jobIds, new TypeReference<List<String>>() {});
|
||||
if (jobIds == null || jobIds.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
return List.of(jobIds.split(","));
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置任务ID列表
|
||||
*/
|
||||
public void setJobIdList(List<String> jobIds) {
|
||||
this.jobIds = JsonUtils.toJsonString(jobIds);
|
||||
this.jobIds = jobIds == null || jobIds.isEmpty() ? null : String.join(",", jobIds);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取输出URL列表
|
||||
*/
|
||||
public List<String> getOutputUrlList() {
|
||||
return JsonUtils.parseObject(outputUrls, new TypeReference<List<String>>() {});
|
||||
if (outputUrls == null || outputUrls.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
return List.of(outputUrls.split(","));
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置输出URL列表
|
||||
*/
|
||||
public void setOutputUrlList(List<String> outputUrls) {
|
||||
this.outputUrls = JsonUtils.toJsonString(outputUrls);
|
||||
this.outputUrls = outputUrls == null || outputUrls.isEmpty() ? null : String.join(",", outputUrls);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,10 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 混剪任务 Service 实现
|
||||
@@ -36,21 +39,21 @@ public class MixTaskServiceImpl implements MixTaskService {
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Long createMixTask(MixTaskSaveReqVO createReqVO, Long userId) {
|
||||
log.info("开始创建混剪任务,用户ID: {}, 标题: {}", userId, createReqVO.getTitle());
|
||||
log.info("[MixTask][创建任务] userId={}, title={}, videoCount={}, produceCount={}",
|
||||
userId, createReqVO.getTitle(), createReqVO.getVideoUrls().size(), createReqVO.getProduceCount());
|
||||
|
||||
// 1. 创建初始任务对象
|
||||
MixTaskDO task = MixTaskUtils.createInitialTask(createReqVO, userId);
|
||||
|
||||
// 2. 保存到数据库
|
||||
mixTaskMapper.insert(task);
|
||||
log.info("任务已创建,任务ID: {}", task.getId());
|
||||
|
||||
// 3. 异步提交到阿里云 ICE
|
||||
CompletableFuture.runAsync(() -> {
|
||||
try {
|
||||
submitToICE(task.getId(), createReqVO);
|
||||
} catch (Exception e) {
|
||||
log.error("提交任务到ICE失败,任务ID: {}", task.getId(), e);
|
||||
log.error("[MixTask][提交ICE失败] taskId={}, error={}", task.getId(), e.getMessage(), e);
|
||||
updateTaskError(task.getId(), "提交任务失败: " + e.getMessage());
|
||||
}
|
||||
});
|
||||
@@ -61,12 +64,10 @@ public class MixTaskServiceImpl implements MixTaskService {
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void updateMixTask(MixTaskUpdateReqVO updateReqVO) {
|
||||
log.info("更新混剪任务,任务ID: {}", updateReqVO.getId());
|
||||
|
||||
// 1. 检查任务是否存在
|
||||
MixTaskDO existTask = mixTaskMapper.selectById(updateReqVO.getId());
|
||||
if (existTask == null) {
|
||||
log.error("任务不存在,任务ID: {}", updateReqVO.getId());
|
||||
log.warn("[MixTask][任务不存在] taskId={}", updateReqVO.getId());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -75,68 +76,58 @@ public class MixTaskServiceImpl implements MixTaskService {
|
||||
|
||||
// 3. 执行更新
|
||||
mixTaskMapper.updateById(updateTask);
|
||||
log.info("任务更新成功,任务ID: {}", updateReqVO.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void deleteMixTask(Long id) {
|
||||
log.info("删除混剪任务,任务ID: {}", id);
|
||||
|
||||
// 1. 检查任务是否存在
|
||||
MixTaskDO existTask = mixTaskMapper.selectById(id);
|
||||
if (existTask == null) {
|
||||
log.error("任务不存在,任务ID: {}", id);
|
||||
log.warn("[MixTask][任务不存在] taskId={}", id);
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. 执行删除
|
||||
mixTaskMapper.deleteById(id);
|
||||
log.info("任务删除成功,任务ID: {}", id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MixTaskRespVO getMixTask(Long id) {
|
||||
log.debug("查询混剪任务,任务ID: {}", id);
|
||||
|
||||
MixTaskDO task = mixTaskMapper.selectById(id);
|
||||
return BeanUtils.toBean(task, MixTaskRespVO.class);
|
||||
MixTaskRespVO respVO = BeanUtils.toBean(task, MixTaskRespVO.class);
|
||||
// 手动设置 outputUrls,因为 DO 中是逗号分隔字符串,VO 中是 List
|
||||
if (respVO != null) {
|
||||
respVO.setOutputUrls(task.getOutputUrlList());
|
||||
}
|
||||
return respVO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageResult<MixTaskRespVO> getMixTaskPage(MixTaskPageReqVO pageReqVO, Long userId) {
|
||||
log.debug("分页查询混剪任务,用户ID: {}, 页码: {}, 页大小: {}",
|
||||
userId, pageReqVO.getPageNo(), pageReqVO.getPageSize());
|
||||
|
||||
PageResult<MixTaskDO> pageResult = mixTaskMapper.selectPage(pageReqVO);
|
||||
return BeanUtils.toBean(pageResult, MixTaskRespVO.class);
|
||||
return convertToRespVO(pageResult);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageResult<MixTaskRespVO> getUserMixTaskPage(MixTaskPageReqVO pageReqVO, Long userId) {
|
||||
log.debug("分页查询用户混剪任务,用户ID: {}, 页码: {}, 页大小: {}",
|
||||
userId, pageReqVO.getPageNo(), pageReqVO.getPageSize());
|
||||
|
||||
// 使用用户ID过滤查询
|
||||
PageResult<MixTaskDO> pageResult = mixTaskMapper.selectPageByUserId(pageReqVO, userId);
|
||||
return BeanUtils.toBean(pageResult, MixTaskRespVO.class);
|
||||
return convertToRespVO(pageResult);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MixTaskRespVO getTaskStatus(Long id) {
|
||||
log.debug("查询任务状态,任务ID: {}", id);
|
||||
return getMixTask(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void retryTask(Long id) {
|
||||
log.info("重新生成失败任务,任务ID: {}", id);
|
||||
|
||||
// 1. 查询原任务
|
||||
MixTaskDO existTask = mixTaskMapper.selectById(id);
|
||||
if (existTask == null) {
|
||||
log.error("任务不存在,任务ID: {}", id);
|
||||
log.warn("[MixTask][任务不存在] taskId={}", id);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -146,8 +137,8 @@ public class MixTaskServiceImpl implements MixTaskService {
|
||||
updateTask.setStatus(MixTaskConstants.STATUS_PENDING);
|
||||
updateTask.setProgress(0);
|
||||
updateTask.setErrorMsg(null);
|
||||
updateTask.setJobIds(null);
|
||||
updateTask.setOutputUrls(null);
|
||||
updateTask.setJobIdList(null);
|
||||
updateTask.setOutputUrlList(null);
|
||||
mixTaskMapper.updateById(updateTask);
|
||||
|
||||
// 3. 重新提交到ICE
|
||||
@@ -160,29 +151,26 @@ public class MixTaskServiceImpl implements MixTaskService {
|
||||
saveReqVO.setProduceCount(existTask.getProduceCount());
|
||||
submitToICE(id, saveReqVO);
|
||||
} catch (Exception e) {
|
||||
log.error("重新提交任务失败,任务ID: {}", id, e);
|
||||
log.error("[MixTask][重新提交失败] taskId={}, error={}", id, e.getMessage(), e);
|
||||
updateTaskError(id, "重新提交失败: " + e.getMessage());
|
||||
}
|
||||
});
|
||||
|
||||
log.info("任务重新提交成功,任务ID: {}", id);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void cancelTask(Long id) {
|
||||
log.info("取消任务,任务ID: {}", id);
|
||||
|
||||
// 1. 查询任务
|
||||
MixTaskDO existTask = mixTaskMapper.selectById(id);
|
||||
if (existTask == null) {
|
||||
log.error("任务不存在,任务ID: {}", id);
|
||||
log.warn("[MixTask][任务不存在] taskId={}", id);
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. 检查任务状态
|
||||
if (!MixTaskConstants.STATUS_RUNNING.equals(existTask.getStatus())) {
|
||||
log.warn("任务非运行状态,无法取消,任务ID: {}, 状态: {}", id, existTask.getStatus());
|
||||
log.warn("[MixTask][任务状态不允许取消] taskId={}, currentStatus={}, requiredStatus={}",
|
||||
id, existTask.getStatus(), MixTaskConstants.STATUS_RUNNING);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -195,14 +183,10 @@ public class MixTaskServiceImpl implements MixTaskService {
|
||||
updateTask.setProgress(MixTaskConstants.PROGRESS_COMPLETED);
|
||||
updateTask.setErrorMsg("用户主动取消任务");
|
||||
mixTaskMapper.updateById(updateTask);
|
||||
|
||||
log.info("任务取消成功,任务ID: {}", id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkTaskStatusBatch() {
|
||||
log.debug("开始批量检查任务状态");
|
||||
|
||||
// 性能优化点:
|
||||
// 1. 时间范围限制:只检查最近6小时内的任务(避免检查历史任务)
|
||||
// 2. 数量限制:每次最多检查50个任务(避免单次查询过多)
|
||||
@@ -220,14 +204,11 @@ public class MixTaskServiceImpl implements MixTaskService {
|
||||
);
|
||||
|
||||
if (runningTasks.isEmpty()) {
|
||||
log.debug("没有最近{}小时内运行中的任务,跳过检查", MixTaskConstants.CHECK_HOURS_LIMIT);
|
||||
return;
|
||||
}
|
||||
|
||||
log.info("发现 {} 个最近{}小时内的运行中任务,开始检查状态(最多检查{}个)",
|
||||
runningTasks.size(), MixTaskConstants.CHECK_HOURS_LIMIT, MixTaskConstants.CHECK_BATCH_SIZE);
|
||||
|
||||
// 逐个检查任务状态
|
||||
int failureCount = 0;
|
||||
for (MixTaskDO task : runningTasks) {
|
||||
try {
|
||||
List<String> jobIds = task.getJobIdList();
|
||||
@@ -237,18 +218,15 @@ public class MixTaskServiceImpl implements MixTaskService {
|
||||
syncTaskStatus(task.getId(), jobId);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("检查任务状态失败,任务ID: {}", task.getId(), e);
|
||||
log.error("[MixTask][单个任务检查失败] taskId={}, error={}", task.getId(), e.getMessage(), e);
|
||||
failureCount++;
|
||||
// 单个任务失败不影响其他任务
|
||||
}
|
||||
}
|
||||
|
||||
log.debug("批量检查任务状态完成");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void syncTaskStatus(Long taskId, String jobId) {
|
||||
log.debug("同步任务状态,任务ID: {}, jobId: {}", taskId, jobId);
|
||||
|
||||
try {
|
||||
// 检查任务是否超时(超过12小时则标记为失败)
|
||||
MixTaskDO task = mixTaskMapper.selectById(taskId);
|
||||
@@ -257,7 +235,7 @@ public class MixTaskServiceImpl implements MixTaskService {
|
||||
if (createTime != null) {
|
||||
long hoursPassed = ChronoUnit.HOURS.between(createTime, LocalDateTime.now());
|
||||
if (hoursPassed > 12) {
|
||||
log.warn("[ICE][任务超时,自动标记为失败][taskId={}, 已运行{}小时]", taskId, hoursPassed);
|
||||
log.warn("[MixTask][任务超时自动失败] taskId={}, runHours={}, threshold=12", taskId, hoursPassed);
|
||||
updateTaskError(taskId, "任务执行超时(超过12小时)");
|
||||
return;
|
||||
}
|
||||
@@ -266,12 +244,10 @@ public class MixTaskServiceImpl implements MixTaskService {
|
||||
|
||||
// 调用阿里云 ICE API 查询任务状态
|
||||
String status = iceClient.getMediaProducingJobStatus(jobId);
|
||||
log.debug("[ICE][查询到任务状态][taskId={}, jobId={}, status={}]", taskId, jobId, status);
|
||||
|
||||
// 根据ICE状态更新任务
|
||||
if ("Success".equalsIgnoreCase(status) || "success".equalsIgnoreCase(status)) {
|
||||
// 任务成功完成,更新为100%
|
||||
log.info("[ICE][任务执行成功][taskId={}, jobId={}]", taskId, jobId);
|
||||
updateTaskStatus(taskId, MixTaskConstants.STATUS_SUCCESS, MixTaskConstants.PROGRESS_COMPLETED);
|
||||
} else if ("Failed".equalsIgnoreCase(status) || "failed".equalsIgnoreCase(status) || "Failure".equalsIgnoreCase(status)) {
|
||||
// 任务失败 - 获取详细错误信息
|
||||
@@ -280,25 +256,24 @@ public class MixTaskServiceImpl implements MixTaskService {
|
||||
// 尝试获取更详细的失败信息(如果ICE API支持)
|
||||
errorMsg = "ICE任务执行失败,状态: " + status;
|
||||
} catch (Exception ex) {
|
||||
log.warn("[ICE][获取详细失败信息失败][taskId={}]", taskId, ex);
|
||||
log.warn("[MixTask][获取详细失败信息失败] taskId={}", taskId, ex);
|
||||
}
|
||||
log.error("[ICE][任务执行失败][taskId={}, jobId={}, status={}]", taskId, jobId, status);
|
||||
log.error("[MixTask][ICE任务执行失败] taskId={}, jobId={}, iceStatus={}, errorMsg={}",
|
||||
taskId, jobId, status, errorMsg);
|
||||
updateTaskError(taskId, errorMsg);
|
||||
} else if ("Running".equalsIgnoreCase(status) || "running".equalsIgnoreCase(status) || "Processing".equalsIgnoreCase(status)) {
|
||||
// 任务仍在运行,更新进度为70%
|
||||
updateTaskStatus(taskId, MixTaskConstants.STATUS_RUNNING, 70);
|
||||
log.debug("[ICE][任务执行中][taskId={}, jobId={}, progress=70%]", taskId, jobId);
|
||||
} else if ("Pending".equalsIgnoreCase(status) || "pending".equalsIgnoreCase(status)) {
|
||||
// 任务等待中,更新进度为60%
|
||||
updateTaskStatus(taskId, MixTaskConstants.STATUS_RUNNING, 60);
|
||||
log.debug("[ICE][任务等待中][taskId={}, jobId={}, progress=60%]", taskId, jobId);
|
||||
} else {
|
||||
// 未知状态,记录日志但不更新
|
||||
log.warn("[ICE][未知任务状态][taskId={}, jobId={}, status={}]", taskId, jobId, status);
|
||||
log.warn("[MixTask][未知ICE状态] taskId={}, jobId={}, iceStatus={}", taskId, jobId, status);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("同步任务状态失败,任务ID: {}, jobId: {}", taskId, jobId, e);
|
||||
log.error("[MixTask][状态同步异常] taskId={}, jobId={}, error={}", taskId, jobId, e.getMessage(), e);
|
||||
updateTaskError(taskId, "查询任务状态失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
@@ -306,8 +281,6 @@ public class MixTaskServiceImpl implements MixTaskService {
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void saveTaskResult(Long taskId, List<String> outputUrls) {
|
||||
log.info("保存任务结果,任务ID: {}, 结果数量: {}", taskId, outputUrls.size());
|
||||
|
||||
// 1. 更新任务输出URL
|
||||
MixTaskDO updateTask = new MixTaskDO();
|
||||
updateTask.setId(taskId);
|
||||
@@ -316,16 +289,12 @@ public class MixTaskServiceImpl implements MixTaskService {
|
||||
updateTask.setProgress(MixTaskConstants.PROGRESS_COMPLETED);
|
||||
updateTask.setFinishTime(java.time.LocalDateTime.now());
|
||||
mixTaskMapper.updateById(updateTask);
|
||||
|
||||
log.info("任务结果保存成功,任务ID: {}", taskId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 提交任务到阿里云 ICE
|
||||
*/
|
||||
private void submitToICE(Long taskId, MixTaskSaveReqVO createReqVO) {
|
||||
log.info("提交任务到ICE,任务ID: {}", taskId);
|
||||
|
||||
try {
|
||||
// 1. 更新任务状态为运行中,进度10%
|
||||
updateTaskStatus(taskId, MixTaskConstants.STATUS_RUNNING, MixTaskConstants.PROGRESS_SUBMITTED);
|
||||
@@ -347,10 +316,8 @@ public class MixTaskServiceImpl implements MixTaskService {
|
||||
updateTaskWithResults(taskId, jobIdUrlPair.getJobIds(), jobIdUrlPair.getOutputUrls(),
|
||||
MixTaskConstants.STATUS_RUNNING, MixTaskConstants.PROGRESS_UPLOADED);
|
||||
|
||||
log.info("任务提交到ICE成功,任务ID: {}, jobId数量: {}", taskId, jobIdUrlPair.getJobIds().size());
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("提交任务到ICE失败,任务ID: {}", taskId, e);
|
||||
log.error("[MixTask][ICE提交失败] taskId={}, error={}", taskId, e.getMessage(), e);
|
||||
updateTaskError(taskId, "ICE处理失败: " + e.getMessage());
|
||||
// 注意:异步线程中不抛出异常,避免未处理异常
|
||||
}
|
||||
@@ -360,8 +327,6 @@ public class MixTaskServiceImpl implements MixTaskService {
|
||||
* 提交任务到阿里云 ICE(新版本,使用 IceClient)
|
||||
*/
|
||||
private void submitToIceV2(Long taskId, MixTaskSaveReqVO createReqVO) {
|
||||
log.info("[V2][提交任务到ICE][taskId={}]", taskId);
|
||||
|
||||
try {
|
||||
// 1. 更新任务状态
|
||||
updateTaskStatus(taskId, MixTaskConstants.STATUS_RUNNING, MixTaskConstants.PROGRESS_SUBMITTED);
|
||||
@@ -374,10 +339,8 @@ public class MixTaskServiceImpl implements MixTaskService {
|
||||
// TODO: 这里需要将 BatchProduceAlignment 的逻辑移到 IceClient 中
|
||||
// String jobId = iceClient.submitMediaProducingJob(timeline, outputMediaConfig);
|
||||
|
||||
log.info("[V2][任务提交成功][taskId={}]", taskId);
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("[V2][提交任务失败][taskId={}]", taskId, e);
|
||||
log.error("[MixTask][V2提交失败] taskId={}, error={}", taskId, e.getMessage(), e);
|
||||
updateTaskError(taskId, "ICE处理失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
@@ -434,7 +397,29 @@ public class MixTaskServiceImpl implements MixTaskService {
|
||||
updateTask.setErrorMsg(errorMsg);
|
||||
updateTask.setFinishTime(java.time.LocalDateTime.now());
|
||||
mixTaskMapper.updateById(updateTask);
|
||||
}
|
||||
|
||||
log.error("任务执行失败,任务ID: {}, 错误信息: {}", taskId, errorMsg);
|
||||
/**
|
||||
* 将DO分页结果转换为VO分页结果,消除冗余代码
|
||||
* 优化点:
|
||||
* 1. 使用Map查找替代O(n)流操作,提升性能
|
||||
* 2. 统一outputUrls转换逻辑,避免代码重复
|
||||
*/
|
||||
private PageResult<MixTaskRespVO> convertToRespVO(PageResult<MixTaskDO> pageResult) {
|
||||
if (pageResult == null || pageResult.getList().isEmpty()) {
|
||||
return PageResult.empty(pageResult.getTotal());
|
||||
}
|
||||
|
||||
// 创建Map用于高效查找(O(1)复杂度)替代流操作的O(n)复杂度
|
||||
Map<Long, MixTaskDO> taskMap = pageResult.getList().stream()
|
||||
.collect(Collectors.toMap(MixTaskDO::getId, Function.identity()));
|
||||
|
||||
return BeanUtils.toBean(pageResult, MixTaskRespVO.class, vo -> {
|
||||
MixTaskDO task = taskMap.get(vo.getId());
|
||||
if (task != null) {
|
||||
// 手动设置 outputUrls,因为 DO 中是逗号分隔字符串,VO 中是 List
|
||||
vo.setOutputUrls(task.getOutputUrlList());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user