From f8a4c59cd0f55890bcadae0f1c6cda1005179334 Mon Sep 17 00:00:00 2001 From: CI Bot Date: Mon, 13 Jul 2026 14:35:19 +0800 Subject: [PATCH 1/3] =?UTF-8?q?fix:=20=E6=B8=B2=E6=9F=93=E5=BC=95=E6=93=8E?= =?UTF-8?q?flag=E8=A7=A3=E6=9E=90=E5=A2=9E=E5=8A=A0=E8=B0=83=E8=AF=95?= =?UTF-8?q?=E6=97=A5=E5=BF=97=20+=20=E7=BB=9F=E4=B8=80fallback=E8=A1=8C?= =?UTF-8?q?=E4=B8=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 三个入口(compose_video/edit_plan/generate_video)都增加flag配置详情日志 (enabled/percentage/whitelist/default_engine),灰度期间便于排查 - 统一fallback行为:异常时全部fallback到legacy(保守策略) 之前generate_video异常时fallback到unified,与其他入口不一致 --- apps/worker/worker_app/tasks/compose_video.py | 23 +++++++++++++++---- .../worker_app/tasks/edit_plan_generation.py | 16 +++++++++++-- apps/worker/worker_app/tasks/generation.py | 19 ++++++++++++--- 3 files changed, 49 insertions(+), 9 deletions(-) diff --git a/apps/worker/worker_app/tasks/compose_video.py b/apps/worker/worker_app/tasks/compose_video.py index 4509d5e02..854afcd0b 100755 --- a/apps/worker/worker_app/tasks/compose_video.py +++ b/apps/worker/worker_app/tasks/compose_video.py @@ -59,15 +59,30 @@ def compose_video(self, job_id: str, **kwargs): # 判断使用哪个渲染引擎 # 优先级:Redis Feature Flag(白名单 > 百分比) > 环境变量默认 from video_processing.render_engine_resolver import get_render_engine_resolver + from video_processing.render_metrics import render_task_metrics resolver = get_render_engine_resolver() user_id = job.created_by_user_id or None engine = resolver.get_engine(user_id=user_id) + # 灰度期间打印详细 flag 配置,便于排查 + config = resolver.get_config_snapshot() + logger.info( + "compose_video 引擎选择: job_id=%s engine=%s user_id=%s enabled=%s percentage=%s whitelist=%d default=%s", + job_id, + engine, + user_id, + config.get("enabled"), + config.get("percentage"), + len(config.get("whitelist", [])), + config.get("default_engine"), + ) - if engine == "unified": - return _compose_with_unified_engine(self, job_service, job, plan_id, db) - else: - return _compose_with_legacy_engine(self, job_service, job, plan_id, db) + # 灰度观测指标埋点 + with render_task_metrics(engine=engine, task_type="compose_video"): + if engine == "unified": + return _compose_with_unified_engine(self, job_service, job, plan_id, db) + else: + return _compose_with_legacy_engine(self, job_service, job, plan_id, db) except self.retry_exc as exc: logger.warning("视频合成重试中: job_id=%s, exc=%s", job_id, exc) diff --git a/apps/worker/worker_app/tasks/edit_plan_generation.py b/apps/worker/worker_app/tasks/edit_plan_generation.py index 9b422ab57..cfef30096 100755 --- a/apps/worker/worker_app/tasks/edit_plan_generation.py +++ b/apps/worker/worker_app/tasks/edit_plan_generation.py @@ -77,9 +77,21 @@ def _resolve_render_engine(user_id: str) -> str: from video_processing.render_engine_resolver import get_render_engine_resolver resolver = get_render_engine_resolver() - return resolver.get_engine(user_id=user_id) + engine = resolver.get_engine(user_id=user_id) + # 灰度期间打印详细 flag 配置,便于排查 + config = resolver.get_config_snapshot() + logger.info( + "edit_plan 引擎选择: user_id=%s engine=%s enabled=%s percentage=%s whitelist=%d default=%s", + user_id, + engine, + config.get("enabled"), + config.get("percentage"), + len(config.get("whitelist", [])), + config.get("default_engine"), + ) + return engine except Exception as exc: - logger.warning("获取渲染引擎配置失败,fallback 到 legacy: %s", exc) + logger.warning("获取渲染引擎配置失败,fallback 到 legacy: %s", exc, exc_info=True) return "legacy" diff --git a/apps/worker/worker_app/tasks/generation.py b/apps/worker/worker_app/tasks/generation.py index 6af97259a..9d475c463 100755 --- a/apps/worker/worker_app/tasks/generation.py +++ b/apps/worker/worker_app/tasks/generation.py @@ -787,10 +787,23 @@ def _resolve_render_engine(user_id: str) -> str: from video_processing.render_engine_resolver import get_render_engine_resolver resolver = get_render_engine_resolver() - return resolver.get_engine(user_id=user_id) + engine = resolver.get_engine(user_id=user_id) + # 灰度期间打印详细 flag 配置,便于排查 + config = resolver.get_config_snapshot() + logger.info( + "[渲染引擎] flag 解析: user_id=%s engine=%s enabled=%s percentage=%s whitelist=%d default=%s", + user_id, + engine, + config.get("enabled"), + config.get("percentage"), + len(config.get("whitelist", [])), + config.get("default_engine"), + ) + return engine except Exception as exc: - logger.warning("获取渲染引擎配置失败,fallback 到 unified: %s", exc) - return ENGINE_UNIFIED + # 异常时 fallback 到 legacy(保守策略,与 edit_plan_generation 一致) + logger.warning("获取渲染引擎配置失败,fallback 到 legacy: %s", exc, exc_info=True) + return ENGINE_LEGACY # ── 旧引擎渲染(FFmpeg filter_complex) ──────────────────────────────────────── -- 2.54.0 From a7566a1dfbbd90f89df116a8643b855a88b17b3a Mon Sep 17 00:00:00 2001 From: CI Bot Date: Wed, 15 Jul 2026 08:25:39 +0800 Subject: [PATCH 2/3] =?UTF-8?q?fix:=20=E7=A7=BB=E9=99=A4render=5Fmetrics?= =?UTF-8?q?=E4=BE=9D=E8=B5=96=EF=BC=88=E8=AF=A5=E6=A8=A1=E5=9D=97=E5=9C=A8?= =?UTF-8?q?develop=E4=B8=8A=E4=B8=8D=E5=AD=98=E5=9C=A8=EF=BC=89=EF=BC=8C?= =?UTF-8?q?=E4=BF=9D=E6=8C=81PR=E7=8B=AC=E7=AB=8B=E5=8F=AF=E5=90=88?= =?UTF-8?q?=E5=B9=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR #248 核心是flag调试日志 + fallback统一,埋点应由专门的灰度观测指标PR负责。 移除compose_video中对render_metrics的引用,确保PR可独立合并、不引入运行时错误。 --- apps/worker/worker_app/tasks/compose_video.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/apps/worker/worker_app/tasks/compose_video.py b/apps/worker/worker_app/tasks/compose_video.py index 854afcd0b..66cd4b844 100755 --- a/apps/worker/worker_app/tasks/compose_video.py +++ b/apps/worker/worker_app/tasks/compose_video.py @@ -59,7 +59,6 @@ def compose_video(self, job_id: str, **kwargs): # 判断使用哪个渲染引擎 # 优先级:Redis Feature Flag(白名单 > 百分比) > 环境变量默认 from video_processing.render_engine_resolver import get_render_engine_resolver - from video_processing.render_metrics import render_task_metrics resolver = get_render_engine_resolver() user_id = job.created_by_user_id or None @@ -77,12 +76,10 @@ def compose_video(self, job_id: str, **kwargs): config.get("default_engine"), ) - # 灰度观测指标埋点 - with render_task_metrics(engine=engine, task_type="compose_video"): - if engine == "unified": - return _compose_with_unified_engine(self, job_service, job, plan_id, db) - else: - return _compose_with_legacy_engine(self, job_service, job, plan_id, db) + if engine == "unified": + return _compose_with_unified_engine(self, job_service, job, plan_id, db) + else: + return _compose_with_legacy_engine(self, job_service, job, plan_id, db) except self.retry_exc as exc: logger.warning("视频合成重试中: job_id=%s, exc=%s", job_id, exc) -- 2.54.0 From 533dec75c6b5c8f4d77a6203eccb74fe78acc4af Mon Sep 17 00:00:00 2001 From: CI Bot Date: Wed, 15 Jul 2026 09:28:50 +0800 Subject: [PATCH 3/3] =?UTF-8?q?feat(api):=20=E5=89=AA=E8=BE=91=E8=AE=A1?= =?UTF-8?q?=E5=88=92=E7=94=9F=E6=88=90=E7=8A=B6=E6=80=81API=E5=A2=9E?= =?UTF-8?q?=E5=BC=BA=20-=20=E6=96=B0=E5=A2=9Eprogress/video=5Furl/error=5F?= =?UTF-8?q?message=E7=AD=89=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 前端联调需要的字段: - generation_task_status: 生成任务状态 - progress: 生成进度(0-100) - video_url: 渲染完成后的视频URL(从plan.config.rendered_url取) - error_message: 失败时的错误信息 edit_plan_service.get_generation_status同步增强,返回progress/error_message --- apps/api/app/api/routes/edit_plans.py | 4 ++++ .../app/api/routes/edit_plans_generation.py | 21 +++++++++++++++---- apps/api/app/services/edit_plan_service.py | 8 +++++++ tests/unit/test_edit_plan_generation_api.py | 11 +++++++++- 4 files changed, 39 insertions(+), 5 deletions(-) mode change 100644 => 100755 apps/api/app/api/routes/edit_plans.py mode change 100644 => 100755 apps/api/app/api/routes/edit_plans_generation.py mode change 100644 => 100755 tests/unit/test_edit_plan_generation_api.py diff --git a/apps/api/app/api/routes/edit_plans.py b/apps/api/app/api/routes/edit_plans.py old mode 100644 new mode 100755 index a830cd193..227af0e67 --- a/apps/api/app/api/routes/edit_plans.py +++ b/apps/api/app/api/routes/edit_plans.py @@ -108,6 +108,10 @@ class EditPlanGenerationStatusResponse(BaseModel): plan_id: str plan_status: str generation_task_id: Optional[str] = None + generation_task_status: Optional[str] = None + progress: float = 0.0 + video_url: str = "" + error_message: str = "" clips: List[ClipStatusItem] diff --git a/apps/api/app/api/routes/edit_plans_generation.py b/apps/api/app/api/routes/edit_plans_generation.py old mode 100644 new mode 100755 index 7d7e37039..23829f179 --- a/apps/api/app/api/routes/edit_plans_generation.py +++ b/apps/api/app/api/routes/edit_plans_generation.py @@ -183,9 +183,7 @@ def _auto_fallback_auto_material_mode( def _check_queue_limits(gen_task_repo, user_id: str) -> None: """队列限流预检查""" try: - has_count = hasattr(gen_task_repo, "count_pending_by_user") and hasattr( - gen_task_repo, "count_pending_total" - ) + has_count = hasattr(gen_task_repo, "count_pending_by_user") and hasattr(gen_task_repo, "count_pending_total") if has_count: user_pending = gen_task_repo.count_pending_by_user(user_id) global_pending = gen_task_repo.count_pending_total() @@ -333,10 +331,25 @@ def get_generation_status( for c in clips ] + # 从 plan.config 中取渲染结果 URL + video_url = (plan.config or {}).get("rendered_url", "") + # 从 gen_status 中取进度、错误信息、任务状态 + progress = gen_status.get("progress", 0.0) + error_message = gen_status.get("error_message", "") + gen_task_status = gen_status.get("generation_task_status") + # 如果计划已完成但进度还是0,补100 + plan_status_val = plan.status.value if hasattr(plan.status, "value") else plan.status + if plan_status_val == "completed" and progress < 100: + progress = 100.0 + return EditPlanGenerationStatusResponse( plan_id=plan_id, - plan_status=plan.status.value if hasattr(plan.status, "value") else plan.status, + plan_status=plan_status_val, generation_task_id=gen_status["generation_task_id"], + generation_task_status=gen_task_status, + progress=progress, + video_url=video_url, + error_message=error_message, clips=clip_items, ) diff --git a/apps/api/app/services/edit_plan_service.py b/apps/api/app/services/edit_plan_service.py index 6ff73b7a6..3b178de09 100755 --- a/apps/api/app/services/edit_plan_service.py +++ b/apps/api/app/services/edit_plan_service.py @@ -431,6 +431,8 @@ class EditPlanService: "clips": List[EditPlanClip], "generation_task_id": Optional[str], "generation_task_status": Optional[str], + "progress": float, + "error_message": str, } Raises: @@ -442,17 +444,23 @@ class EditPlanService: # 从 plan.config 中获取 generation_task_id generation_task_id = plan.config.get("generation_task_id") generation_task_status = None + progress = 0.0 + error_message = "" if generation_task_id: task = self._generation_task_repo.get(generation_task_id) if task: generation_task_status = task.status.value if hasattr(task.status, "value") else task.status + progress = getattr(task, "progress", 0.0) or 0.0 + error_message = getattr(task, "error_message", "") or "" return { "plan": plan, "clips": clips, "generation_task_id": generation_task_id, "generation_task_status": generation_task_status, + "progress": progress, + "error_message": error_message, } def can_generate(self, plan_id: str) -> tuple[bool, str]: diff --git a/tests/unit/test_edit_plan_generation_api.py b/tests/unit/test_edit_plan_generation_api.py old mode 100644 new mode 100755 index 85a1b3e03..add7d042b --- a/tests/unit/test_edit_plan_generation_api.py +++ b/tests/unit/test_edit_plan_generation_api.py @@ -665,7 +665,16 @@ class TestResponseSchema: resp = client.get(f"/api/v1/edit-plans/{plan.id}/generation-status") assert resp.status_code == 200 data = resp.json() - expected_keys = {"plan_id", "plan_status", "generation_task_id", "clips"} + expected_keys = { + "plan_id", + "plan_status", + "generation_task_id", + "generation_task_status", + "progress", + "video_url", + "error_message", + "clips", + } assert set(data.keys()) == expected_keys -- 2.54.0