refactor(A2): replace blender-renderer HTTP service with render-worker Celery container
- Create render-worker/ with Dockerfile (Ubuntu + cadquery + Blender via host mount) - Add render-worker/check_version.py: verifies Blender >= 5.0.1 at startup, Exit 1 on failure - Add render-worker/scripts/: blender_render.py, still_render.py, turntable_render.py - Create backend/app/services/render_blender.py: direct subprocess rendering - convert_step_to_stl() and export_per_part_stls() using cadquery - render_still(): STEP → STL → PNG via Blender subprocess - is_blender_available(): detects BLENDER_BIN env for render-worker context - Create backend/app/domains/rendering/tasks.py: render_still_task + render_turntable_task - Update step_processor.py: use subprocess path when BLENDER_BIN env is set (render-worker) - Update step_tasks.py: generate_stl_cache uses direct cadquery instead of HTTP - Remove blender-renderer and threejs-renderer from docker-compose.yml - Replace worker-thumbnail with render-worker (Ubuntu + cadquery + Blender mount) - Remove Docker SDK from backend Dockerfile (was only for flamenco scaling) - Update .env.example: BLENDER_VERSION=5.0.1 documented - Update celery_app.py: include domains.rendering.tasks in autodiscover Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,68 @@
|
||||
"""Startup check: verify Blender >= 5.0.1 is available.
|
||||
|
||||
Run before starting the Celery worker. Exits with code 1 if Blender is
|
||||
missing or below the minimum required version.
|
||||
"""
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
MIN_VERSION = (5, 0, 1)
|
||||
MIN_VERSION_STR = ".".join(str(v) for v in MIN_VERSION)
|
||||
|
||||
|
||||
def find_blender() -> str:
|
||||
import shutil
|
||||
env_bin = os.environ.get("BLENDER_BIN", "")
|
||||
if env_bin and Path(env_bin).exists():
|
||||
return env_bin
|
||||
found = shutil.which("blender")
|
||||
return found or "blender"
|
||||
|
||||
|
||||
def check_version():
|
||||
blender_bin = find_blender()
|
||||
|
||||
if not Path(blender_bin).exists():
|
||||
print(f"ERROR: Blender not found at {blender_bin}", file=sys.stderr)
|
||||
print(
|
||||
"Mount Blender >= 5.0.1 from the host via:\n"
|
||||
" volumes:\n"
|
||||
" - /opt/blender:/opt/blender:ro",
|
||||
file=sys.stderr,
|
||||
)
|
||||
sys.exit(1)
|
||||
|
||||
try:
|
||||
result = subprocess.run(
|
||||
[blender_bin, "--version"],
|
||||
capture_output=True, text=True, timeout=15
|
||||
)
|
||||
output = result.stdout or result.stderr or ""
|
||||
except Exception as exc:
|
||||
print(f"ERROR: Could not run Blender: {exc}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
match = re.search(r"Blender\s+(\d+)\.(\d+)\.(\d+)", output)
|
||||
if not match:
|
||||
print(f"ERROR: Could not parse Blender version from output:\n{output[:200]}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
version = tuple(int(x) for x in match.groups())
|
||||
version_str = ".".join(str(v) for v in version)
|
||||
|
||||
if version < MIN_VERSION:
|
||||
print(
|
||||
f"ERROR: Blender {version_str} < required {MIN_VERSION_STR}.\n"
|
||||
f"Update your host Blender installation.",
|
||||
file=sys.stderr,
|
||||
)
|
||||
sys.exit(1)
|
||||
|
||||
print(f"Blender {version_str} OK (>= {MIN_VERSION_STR})")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
check_version()
|
||||
Reference in New Issue
Block a user