feat(refactor/phase2): pipeline modularity + dead code removal

Phase 2.3 — Fix render cancellation (real Celery task ID):
  - orders.py cancel endpoints: read celery_task_id from render_job_doc
    instead of synthetic "render-{line_id}" which was a no-op
  - render_order_line_still_task: creates RenderJobDocument at task start,
    stores self.request.id as celery_task_id, writes step-level state
    (RESOLVE_STEP_PATH → BLENDER_STILL) back to order_lines.render_job_doc

Phase 3.1 — Remove Pillow overlay dead code:
  - blender_render.py: deleted 55-line Pillow post-processing block
    (lines 798-851, green bar + model name label)
  - transparent_bg=True is always passed; the else branch was unreachable
  - Removed mention from script docstring

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-08 19:27:33 +01:00
parent ea31ed657c
commit 966c3aed57
4 changed files with 200 additions and 64 deletions
+12 -8
View File
@@ -954,12 +954,14 @@ async def cancel_line_render(
cancelled_backend = line.render_backend_used or "celery"
errors: list[str] = []
# Revoke Celery task (best-effort)
# Revoke Celery task (best-effort) using real task ID from job document
try:
from app.tasks.celery_app import celery_app
celery_app.control.revoke(
f"render-{line_id}", terminate=True, signal="SIGTERM"
)
real_task_id = None
if line.render_job_doc:
real_task_id = line.render_job_doc.get("celery_task_id")
task_id = real_task_id or f"render-{line_id}"
celery_app.control.revoke(task_id, terminate=True, signal="SIGTERM")
except Exception as exc:
errors.append(f"Celery revoke failed: {str(exc)[:200]}")
@@ -1025,11 +1027,13 @@ async def cancel_order_renders(
errors: list[str] = []
for line in lines:
# Revoke Celery task (best-effort)
# Revoke Celery task using real task ID from job document
try:
celery_app.control.revoke(
f"render-{line.id}", terminate=True, signal="SIGTERM"
)
real_task_id = None
if line.render_job_doc:
real_task_id = line.render_job_doc.get("celery_task_id")
task_id = real_task_id or f"render-{line.id}"
celery_app.control.revoke(task_id, terminate=True, signal="SIGTERM")
except Exception:
pass
+48
View File
@@ -395,14 +395,47 @@ def render_order_line_still_task(self, order_line_id: str, **params) -> dict:
Wraps render_still_task logic but accepts order_line_id instead of step_path.
On success, creates a MediaAsset record via publish_asset.
"""
import asyncio
from app.domains.rendering.job_document import RenderJobDocument, JobState
from app.core.process_steps import StepName
log_task_event(self.request.id, f"Starting render_order_line_still_task: order_line={order_line_id}", "info")
# Initialise job document and store real Celery task ID
job_doc = RenderJobDocument.new(order_line_id=order_line_id, celery_task_id=self.request.id)
job_doc.set_state(JobState.RUNNING)
def _save_job_doc():
async def _run():
from app.database import AsyncSessionLocal
from app.domains.orders.models import OrderLine
from sqlalchemy import update as _upd
async with AsyncSessionLocal() as db:
await db.execute(
_upd(OrderLine)
.where(OrderLine.id == order_line_id)
.values(render_job_doc=job_doc.to_dict())
)
await db.commit()
try:
asyncio.get_event_loop().run_until_complete(_run())
except Exception as _exc:
logger.debug("_save_job_doc failed: %s", _exc)
_save_job_doc()
job_doc.begin_step(StepName.RESOLVE_STEP_PATH)
step_path_str, cad_file_id = _resolve_step_path_for_order_line(order_line_id)
if not step_path_str:
job_doc.fail_step(StepName.RESOLVE_STEP_PATH, "product missing or has no linked CAD file")
job_doc.set_state(JobState.FAILED, error="Cannot resolve STEP path")
_save_job_doc()
log_task_event(self.request.id, f"Failed: cannot resolve STEP path for order_line {order_line_id}", "error")
raise RuntimeError(
f"Cannot resolve STEP path for order_line {order_line_id}: "
"product missing or has no linked CAD file"
)
job_doc.finish_step(StepName.RESOLVE_STEP_PATH, output={"step_path": step_path_str})
step = Path(step_path_str)
output_dir = step.parent / "renders"
@@ -410,12 +443,24 @@ def render_order_line_still_task(self, order_line_id: str, **params) -> dict:
output_path = output_dir / f"line_{order_line_id}.png"
try:
job_doc.begin_step(StepName.BLENDER_STILL)
from app.services.render_blender import render_still
result = render_still(
step_path=step,
output_path=output_path,
**params,
)
job_doc.finish_step(
StepName.BLENDER_STILL,
output={"output_path": str(output_path), "duration_s": result.get("total_duration_s")},
)
job_doc.set_state(JobState.COMPLETED, result={
"output_path": str(output_path),
"duration_s": result.get("total_duration_s"),
"engine_used": result.get("engine_used"),
})
_save_job_doc()
publish_asset.delay(
order_line_id,
"still",
@@ -438,6 +483,9 @@ def render_order_line_still_task(self, order_line_id: str, **params) -> dict:
_update_workflow_run_status(order_line_id, "completed")
return result
except Exception as exc:
job_doc.fail_step(StepName.BLENDER_STILL, str(exc))
job_doc.set_state(JobState.FAILED, error=str(exc))
_save_job_doc()
log_task_event(self.request.id, f"Failed: {exc}", "error")
logger.error("render_order_line_still_task failed for %s: %s", order_line_id, exc)
try: