fix(media): 转码错误信息截断并上报进度
This commit is contained in:
1 parent
f9bc6eee6d
commit
660afaf66d
18 files changed
+469
-34
No files matched your search
+5
-1
@@ -12,6 +12,7 @@ import java.nio.file.Path;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
@@ -40,13 +41,15 @@ class FfmpegTranscodeRunnerSmokeTest {
|
||||
|
||||
Path output = work.resolve("out");
|
||||
TranscodeRunner runner = new FfmpegTranscodeRunner();
|
||||
AtomicInteger maxProgress = new AtomicInteger();
|
||||
// 只跑两档(360p/480p)保持秒级;四档阶梯的逻辑在 TranscodeWorkerTest 里断言
|
||||
TranscodeRunner.TranscodeResult result = runner.run(new TranscodeRunner.TranscodeRequest(
|
||||
1L, sample, output, "transcoded/smoke",
|
||||
List.of(new TranscodeRunner.LadderRung("360p", 640, 360, 400, 64),
|
||||
new TranscodeRunner.LadderRung("480p", 854, 480, 800, 64)),
|
||||
ffmpeg, ffprobe, 2, 1, 120,
|
||||
new TranscodeRunner.SpriteOptions(true, 1, 10, 160)));
|
||||
new TranscodeRunner.SpriteOptions(true, 1, 10, 160),
|
||||
value -> maxProgress.accumulateAndGet(value, Math::max)));
|
||||
|
||||
assertThat(Files.exists(output.resolve("master.m3u8"))).isTrue();
|
||||
assertThat(Files.exists(output.resolve("poster.jpg"))).isTrue();
|
||||
@@ -60,6 +63,7 @@ class FfmpegTranscodeRunnerSmokeTest {
|
||||
assertThat(rendition.sizeBytes()).isGreaterThan(0L);
|
||||
}
|
||||
assertThat(result.durationSec()).isBetween(1, 5);
|
||||
assertThat(maxProgress.get()).isGreaterThanOrEqualTo(90);
|
||||
assertThat(result.thumbnail()).isNotNull();
|
||||
assertThat(result.thumbnail().status()).isEqualTo("READY");
|
||||
assertThat(result.thumbnail().thumbWidth()).isEqualTo(160);
|
||||
|
||||
+33
-14
@@ -21,7 +21,6 @@ import org.junit.jupiter.api.Test;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
@@ -54,24 +53,22 @@ class TranscodeServiceTriggerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_create_once_and_reuse_queued_task_when_retrying_successful_asset() {
|
||||
void should_reset_completed_task_in_place_and_reuse_it_when_triggered_again() {
|
||||
TranscodeTask success = task(10L, TranscodeService.STATUS_SUCCESS);
|
||||
TranscodeTask queued = task(100L, TranscodeService.STATUS_QUEUED);
|
||||
given(taskMapper.selectOne(any())).willReturn(success, null, queued);
|
||||
doAnswer(invocation -> {
|
||||
TranscodeTask inserted = invocation.getArgument(0);
|
||||
inserted.setId(100L);
|
||||
return 1;
|
||||
}).when(taskMapper).insert(any(TranscodeTask.class));
|
||||
queued.setId(10L);
|
||||
given(taskMapper.selectOne(any())).willReturn(success, queued);
|
||||
given(taskMapper.update(any(), any())).willReturn(1);
|
||||
|
||||
TranscodeTriggerRespVO first = transcodeService.trigger(ASSET_ID, "/files/video.mp4");
|
||||
TranscodeTriggerRespVO second = transcodeService.trigger(ASSET_ID, "/files/video.mp4");
|
||||
|
||||
assertThat(first.getTaskId()).isEqualTo(100L);
|
||||
assertThat(first.getTaskId()).isEqualTo(10L);
|
||||
assertThat(first.getStatus()).isEqualTo(TranscodeService.STATUS_QUEUED);
|
||||
assertThat(second.getTaskId()).isEqualTo(100L);
|
||||
assertThat(second.getTaskId()).isEqualTo(10L);
|
||||
assertThat(second.getStatus()).isEqualTo(TranscodeService.STATUS_QUEUED);
|
||||
verify(taskMapper).insert(any(TranscodeTask.class));
|
||||
verify(taskMapper, never()).insert(any(TranscodeTask.class));
|
||||
verify(taskMapper).update(any(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -111,17 +108,39 @@ class TranscodeServiceTriggerTest {
|
||||
TranscodeTask running = task(41L, TranscodeService.STATUS_RUNNING);
|
||||
running.setRetryCount(2);
|
||||
given(taskMapper.selectById(41L)).willReturn(running);
|
||||
String longReason = "ffmpeg 输出异常:" + "x".repeat(5000);
|
||||
|
||||
String status = transcodeService.fail(
|
||||
41L, "ffmpeg 退出码 1:Invalid data found");
|
||||
String status = transcodeService.fail(41L, longReason);
|
||||
|
||||
assertThat(status).isEqualTo(TranscodeService.STATUS_FAILED);
|
||||
assertThat(running.getStatus()).isEqualTo(TranscodeService.STATUS_FAILED);
|
||||
assertThat(running.getRetryCount()).isEqualTo(3);
|
||||
assertThat(running.getErrorMsg()).contains("Invalid data found");
|
||||
assertThat(running.getErrorMsg()).contains("ffmpeg 输出异常");
|
||||
assertThat(running.getErrorMsg()).contains("truncated");
|
||||
assertThat(running.getErrorMsg()).contains("total=" + longReason.length());
|
||||
assertThat(running.getErrorMsg().length()).isLessThanOrEqualTo(500);
|
||||
verify(taskMapper).updateById(running);
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_update_progress_only_for_running_task() {
|
||||
given(taskMapper.update(any(), any())).willReturn(1);
|
||||
|
||||
transcodeService.updateProgress(51L, 46);
|
||||
|
||||
verify(taskMapper).update(any(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_mark_stale_running_task_failed() {
|
||||
given(taskMapper.update(any(), any())).willReturn(2);
|
||||
|
||||
int recovered = transcodeService.recoverStaleRunningTasks();
|
||||
|
||||
assertThat(recovered).isEqualTo(2);
|
||||
verify(taskMapper).update(any(), any());
|
||||
}
|
||||
|
||||
private TranscodeTask task(Long id, String status) {
|
||||
TranscodeTask task = new TranscodeTask();
|
||||
task.setId(id);
|
||||
|
||||
+10
-1
@@ -72,6 +72,7 @@ class TranscodeWorkerTest {
|
||||
@Test
|
||||
void should_register_renditions_and_mark_asset_ready_when_transcode_succeeds() {
|
||||
given(transcodeService.claimNext()).willReturn(queuedTask());
|
||||
runner.progress = 45;
|
||||
|
||||
assertThat(worker.processOne()).isTrue();
|
||||
|
||||
@@ -92,6 +93,7 @@ class TranscodeWorkerTest {
|
||||
eq("/files/transcoded/88/poster.jpg"), eq(120));
|
||||
verify(episodeCompletionPort).markEpisodeReady(
|
||||
12L, "/files/transcoded/88/master.m3u8", 120);
|
||||
verify(transcodeService).updateProgress(TASK_ID, 45);
|
||||
verify(transcodeService, never()).fail(any(), anyString());
|
||||
}
|
||||
|
||||
@@ -110,11 +112,12 @@ class TranscodeWorkerTest {
|
||||
@Test
|
||||
void should_keep_main_transcode_successful_when_thumbnail_generation_fails() {
|
||||
given(transcodeService.claimNext()).willReturn(queuedTask());
|
||||
String thumbnailError = "tile 滤镜失败:" + "x".repeat(5000);
|
||||
runner.thumbnail = new TranscodeRunner.ProducedThumbnail(
|
||||
"transcoded/88/thumbnails/thumbnails.vtt",
|
||||
"transcoded/88/thumbnails/sprite_",
|
||||
1, 10, 1, 160, 0, 120, 120, 0L,
|
||||
MediaThumbnail.STATUS_FAILED, "tile 滤镜失败");
|
||||
MediaThumbnail.STATUS_FAILED, thumbnailError);
|
||||
|
||||
worker.processOne();
|
||||
|
||||
@@ -128,6 +131,8 @@ class TranscodeWorkerTest {
|
||||
assertThat(thumbnail.getValue().getStatus())
|
||||
.isEqualTo(MediaThumbnail.STATUS_FAILED);
|
||||
assertThat(thumbnail.getValue().getErrorMsg()).contains("tile");
|
||||
assertThat(thumbnail.getValue().getErrorMsg()).contains("truncated");
|
||||
assertThat(thumbnail.getValue().getErrorMsg().length()).isLessThanOrEqualTo(500);
|
||||
verify(mediaService).markReady(eq(ASSET_ID), anyString(), anyString(), eq(120));
|
||||
verify(transcodeService, never()).fail(any(), anyString());
|
||||
}
|
||||
@@ -190,12 +195,16 @@ class TranscodeWorkerTest {
|
||||
private TranscodeRequest request;
|
||||
private RuntimeException failure;
|
||||
private ProducedThumbnail thumbnail;
|
||||
private Integer progress;
|
||||
private boolean called;
|
||||
|
||||
@Override
|
||||
public TranscodeResult run(TranscodeRequest request) {
|
||||
this.request = request;
|
||||
this.called = true;
|
||||
if (progress != null) {
|
||||
request.progressListener().accept(progress);
|
||||
}
|
||||
if (failure != null) {
|
||||
throw failure;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user