fix(ingest): separate ffprobe and ffmpeg timeout handling in HEVC transcode (#1454)
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m10s
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 2m47s
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 3m10s
CI/CD Pipeline / Build Staging API Image (push) Successful in 3m14s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 3m15s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m23s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 4m55s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 56s
CI/CD Pipeline / Staging E2E Tests (push) Failing after 1m26s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m11s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 8m48s
CI/CD Pipeline / Unit Tests (push) Successful in 12m29s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Integration Tests (push) Successful in 5m48s
CI/CD Pipeline / CI Gate (push) Has been skipped

Co-authored-by: xiaoxia <dev@xiaoxiajianji.com>
Co-committed-by: xiaoxia <dev@xiaoxiajianji.com>
This commit was merged in pull request #1454.
This commit is contained in:
2026-08-21 11:26:01 +08:00
committed by auto-approve-bot
parent 3441b3fece
commit f08a2bfa0d
+26 -6
View File
@@ -248,14 +248,18 @@ def ingest_asset(job_id: str) -> dict:
)
_tc_tmp = None
_needs_rotation = False
# ── Step 1: 磁盘空间检查(独立 try/except,失败仍尝试转码)──
try:
# 检查磁盘空间(大文件转码需要至少 2GB 可用空间)
_disk_usage = shutil.disk_usage("/tmp")
_free_gb = _disk_usage.free / (1024**3)
if _free_gb < 2:
raise RuntimeError(f"磁盘空间不足 ({_free_gb:.1f}GB < 2GB),无法处理大文件")
raise RuntimeError(f"磁盘空间不足 ({_free_gb:.1f}GB < 2GB)")
except Exception as _disk_err:
logger.warning("磁盘检查失败,仍尝试转码: job_id=%s err=%s", job_id, _disk_err)
# 检测视频是否有 rotation 元数据(竖屏视频)
# ── Step 2: ffprobe 旋转检测(独立 try/except,失败不阻塞转码)──
try:
_probe_cmd = [
"ffprobe",
"-v",
@@ -275,7 +279,7 @@ def ingest_asset(job_id: str) -> dict:
stdout=subprocess.PIPE,
stderr=subprocess.DEVNULL,
text=True,
timeout=10,
timeout=60, # 大文件在容器 overlay 文件系统上解析可能较慢
)
_rotation_str = (_probe_result.stdout or "").strip().split("\n")[0]
if _rotation_str in ("90", "270", "-90"):
@@ -285,7 +289,22 @@ def ingest_asset(job_id: str) -> dict:
_rotation_str,
job_id,
)
except subprocess.TimeoutExpired:
logger.warning(
"ffprobe 旋转检测超时(60s),跳过旋转继续转码: job_id=%s",
job_id,
)
_needs_rotation = False
except Exception as _probe_err:
logger.warning(
"ffprobe 旋转检测异常,跳过旋转继续转码: job_id=%s err=%s",
job_id,
_probe_err,
)
_needs_rotation = False
# ── Step 3: ffmpeg 转码(独立 try/except)──
try:
_tc_tmp_file = tempfile.NamedTemporaryFile(delete=False, suffix="_h264.mp4")
_tc_tmp = Path(_tc_tmp_file.name)
_tc_tmp_file.close() # 关闭文件描述符,ffmpeg 会自己打开
@@ -370,13 +389,14 @@ def ingest_asset(job_id: str) -> dict:
else:
_tail = _proc.stderr[-300:] if _proc.stderr else ""
logger.warning(
"FFmpeg 转码失败 rc=%s,降级原始文件: job_id=%s",
"FFmpeg 转码失败 rc=%s stderr=%s: job_id=%s",
_proc.returncode,
_tail,
job_id,
)
except subprocess.TimeoutExpired:
logger.warning(
"FFmpeg 转码超时 (900s),降级原始文件: job_id=%s",
"FFmpeg 转码超时(900s),降级原始文件: job_id=%s",
job_id,
)
except Exception as _e: