feat: extract workflow notifications phase 3

This commit is contained in:
2026-04-07 09:57:39 +02:00
parent 160c198bb3
commit 98b3eadcb2
6 changed files with 291 additions and 63 deletions
@@ -5,6 +5,7 @@ Covers:
- render_order_line_task — full still/turntable render pipeline for one order line
"""
import logging
from datetime import datetime
from app.tasks.celery_app import celery_app
from app.core.task_logs import log_task_event
@@ -70,10 +71,11 @@ def render_order_line_task(self, order_line_id: str):
emit(order_line_id, "Celery render task started")
try:
from sqlalchemy import create_engine, select
from sqlalchemy import create_engine
from sqlalchemy.orm import Session
from app.config import settings as app_settings
from app.domains.rendering.workflow_runtime_services import (
emit_order_line_render_notifications,
persist_order_line_output,
prepare_order_line_render_context,
resolve_order_line_template_context,
@@ -455,7 +457,6 @@ def render_order_line_task(self, order_line_id: str):
else:
pl.step_error("blender_still", "render_to_file returned False")
new_status = "completed" if success else "failed"
render_end = datetime.utcnow()
elapsed = (render_end - render_start).total_seconds()
try:
@@ -476,51 +477,18 @@ def render_order_line_task(self, order_line_id: str):
else:
emit(order_line_id, f"Render failed after {elapsed:.1f}s", "error")
# Broadcast WebSocket event for live UI updates
try:
from app.core.websocket import publish_event_sync
_tenant_id = str(line.product.cad_file.tenant_id) if (
emit_order_line_render_notifications(
success=success,
order_line_id=order_line_id,
tenant_id=str(line.product.cad_file.tenant_id) if (
line.product and line.product.cad_file and line.product.cad_file.tenant_id
) else None
if _tenant_id:
publish_event_sync(_tenant_id, {
"type": "render_complete" if success else "render_failed",
"order_line_id": order_line_id,
"order_id": str(line.order_id),
"status": new_status,
})
except Exception:
logger.debug("WebSocket publish skipped (non-fatal)")
# Emit per-render activity event (channel=activity, not shown in bell dropdown)
try:
from app.models.order import Order as OrderModel
order_row = session.execute(
select(OrderModel.created_by, OrderModel.order_number)
.where(OrderModel.id == line.order_id)
).one_or_none()
if order_row:
from app.services.notification_service import emit_notification_sync, CHANNEL_ACTIVITY
details: dict = {
"order_number": order_row[1],
"product_name": product_name,
"output_type": ot_name,
}
if not success and isinstance(render_log, dict):
err = render_log.get("error") or render_log.get("stderr", "")
if err:
details["error"] = str(err)[:300]
emit_notification_sync(
actor_user_id=None,
target_user_id=str(order_row[0]),
action="render.completed" if success else "render.failed",
entity_type="order",
entity_id=str(line.order_id),
details=details,
channel=CHANNEL_ACTIVITY,
)
except Exception:
logger.exception("Failed to emit render activity event")
) else None,
product_name=product_name,
output_type_name=ot_name,
render_log=render_log if isinstance(render_log, dict) else None,
session=session,
line=line,
)
# Check if all lines for this order are done → auto-advance
order_id_str = str(line.order_id)
@@ -571,6 +539,9 @@ def render_order_line_task(self, order_line_id: str):
try:
from sqlalchemy import select as sel2
from app.models.order import Order as OrderModel2
from app.domains.rendering.workflow_runtime_services import (
emit_order_line_render_notifications,
)
eng4 = create_engine(sync_url2)
with SyncSession(eng4) as s4:
set_tenant_context_sync(s4, _tenant_id)
@@ -581,20 +552,16 @@ def render_order_line_task(self, order_line_id: str):
).one_or_none()
eng4.dispose()
if order_row2:
from app.services.notification_service import emit_notification_sync, CHANNEL_ACTIVITY
emit_notification_sync(
actor_user_id=None,
target_user_id=str(order_row2[0]),
action="render.failed",
entity_type="order",
entity_id=None,
details={
"order_number": order_row2[1],
"product_name": "unknown",
"output_type": "unknown",
"error": str(exc)[:300],
},
channel=CHANNEL_ACTIVITY,
emit_order_line_render_notifications(
success=False,
order_line_id=order_line_id,
order_number=order_row2[1],
order_creator_id=str(order_row2[0]),
product_name="unknown",
output_type_name="unknown",
render_log={"error": str(exc)},
emit_websocket=False,
activity_entity_id=None,
)
except Exception:
logger.exception("Failed to emit render failure activity event")