fix(media): 清理旧 rendition 并确保失败状态落库

This commit is contained in:
Zhou Weidong committed 2026-10-22 15:36:35 +08:00
1 parent 5d1a157085
commit 91b621fe75
9 files changed
+226 -35

No files matched your search

@@ -27,18 +27,12 @@ public class ThumbnailRecordService {
if (episodeId == null || episodeId <= 0) {
return;
}
MediaThumbnail existing = mediaThumbnailMapper.selectOne(
Wrappers.<MediaThumbnail>lambdaQuery()
.eq(MediaThumbnail::getEpisodeId, episodeId)
.last("limit 1"));
thumbnail.setDramaId(task.getDramaId() == null ? 0L : task.getDramaId());
thumbnail.setEpisodeId(episodeId);
thumbnail.setErrorMsg(TranscodeErrorTruncator.truncate(thumbnail.getErrorMsg()));
if (existing == null) {
mediaThumbnailMapper.insert(thumbnail);
return;
}
thumbnail.setId(existing.getId());
mediaThumbnailMapper.updateById(thumbnail);
thumbnail.setId(null);
mediaThumbnailMapper.delete(Wrappers.<MediaThumbnail>lambdaQuery()
.eq(MediaThumbnail::getEpisodeId, episodeId));
mediaThumbnailMapper.insert(thumbnail);
}
}
@@ -7,7 +7,7 @@ public final class TranscodeErrorTruncator {
public static final int MAX_ERROR_CHARS = 500;
private static final String EMPTY = "";
private static final String TRUNCATED_TEMPLATE = "…(truncated, total=%d chars)";
private static final String TRUNCATED_TEMPLATE = "…(truncated, total=%d chars)…";
private TranscodeErrorTruncator() {
}
@@ -17,7 +17,10 @@ public final class TranscodeErrorTruncator {
return message == null ? EMPTY : message;
}
String suffix = String.format(TRUNCATED_TEMPLATE, message.length());
int prefixLength = Math.max(0, MAX_ERROR_CHARS - suffix.length());
return message.substring(0, prefixLength) + suffix;
int remain = Math.max(0, MAX_ERROR_CHARS - suffix.length());
int prefixLength = remain / 2;
int tailLength = remain - prefixLength;
return message.substring(0, prefixLength)
+ suffix + message.substring(message.length() - tailLength);
}
}
@@ -217,8 +217,15 @@ public class TranscodeService {
public void succeed(Long taskId, List<MediaRendition> renditions,
MediaThumbnail thumbnail) {
TranscodeTask task = getExisting(taskId);
mediaRenditionMapper.delete(Wrappers.<MediaRendition>lambdaQuery()
.eq(MediaRendition::getMediaAssetId, task.getMediaAssetId()));
var renditionDelete = Wrappers.<MediaRendition>lambdaQuery();
if (task.getEpisodeId() != null && task.getEpisodeId() > 0) {
renditionDelete.and(wrapper -> wrapper
.eq(MediaRendition::getMediaAssetId, task.getMediaAssetId())
.or().eq(MediaRendition::getEpisodeId, task.getEpisodeId()));
} else {
renditionDelete.eq(MediaRendition::getMediaAssetId, task.getMediaAssetId());
}
mediaRenditionMapper.delete(renditionDelete);
for (MediaRendition rendition : renditions) {
rendition.setMediaAssetId(task.getMediaAssetId());
rendition.setDramaId(task.getDramaId());
@@ -277,6 +284,23 @@ public class TranscodeService {
.set(TranscodeTask::getProgress, safeProgress));
}
/** 主流程异常时立即终止任务,保留最后进度并写入截断后的错误。 */
public int failFinal(Long taskId, String errorMessage) {
if (taskId == null) {
return 0;
}
int updated = transcodeTaskMapper.update(null, Wrappers.<TranscodeTask>lambdaUpdate()
.eq(TranscodeTask::getId, taskId)
.set(TranscodeTask::getStatus, STATUS_FAILED)
.set(TranscodeTask::getErrorMsg,
TranscodeErrorTruncator.truncate(errorMessage))
.set(TranscodeTask::getFinishedAt, LocalDateTime.now()));
if (updated == 0) {
log.error("转码任务失败状态落库失败:task={} 不存在或未更新", taskId);
}
return updated;
}
/** RUNNING 超过阈值且 updated_at 长期未变时自动收口,避免僵尸任务永久占位。 */
public int recoverStaleRunningTasks() {
LocalDateTime now = LocalDateTime.now();
@@ -116,15 +116,23 @@ public class TranscodeWorker {
logThumbnailResult(result.thumbnail());
} catch (Exception ex) {
String reason = ex.getMessage() == null ? ex.getClass().getSimpleName() : ex.getMessage();
int attempt = (task.getRetryCount() == null ? 0 : task.getRetryCount()) + 1;
String status = transcodeService.fail(task.getId(), reason);
if (TranscodeService.STATUS_FAILED.equals(status)
&& task.getMediaAssetId() != null && task.getMediaAssetId() > 0) {
mediaService.markFailed(task.getMediaAssetId(), reason);
try {
transcodeService.failFinal(task.getId(), reason);
} catch (Exception persistError) {
log.error("转码任务失败状态落库失败 task={} 原因={}",
task.getId(), persistError.getMessage(), persistError);
}
log.error("转码失败 task={} 第 {}/{} 次尝试 耗时={}ms 结果={} 原因={}",
task.getId(), attempt, TranscodeService.MAX_RETRY, System.currentTimeMillis() - startedAt,
status, reason);
if (task.getMediaAssetId() != null && task.getMediaAssetId() > 0) {
try {
mediaService.markFailed(task.getMediaAssetId(), reason);
} catch (Exception mediaError) {
log.error("媒资失败状态落库失败 asset={} 原因={}",
task.getMediaAssetId(), mediaError.getMessage(), mediaError);
}
}
log.error("转码失败 task={} 耗时={}ms 结果=FAILED 原因={}",
task.getId(), System.currentTimeMillis() - startedAt,
TranscodeErrorTruncator.truncate(reason));
}
}