import logging from typing import Any, Dict from celery import shared_task logger = logging.getLogger("celery_tasks") if not logger.handlers: _h = logging.StreamHandler() logger.addHandler(_h) logger.setLevel(logging.INFO) @shared_task(name="workers.send_email") def send_email(payload: Dict[str, Any]) -> None: """Celery task to send an email. Expected payload schema: { "type": "email", "to": "recipient@example.com", "subject": "Subject text", "body": "Email body text" } This mirrors the previous queue worker contract to minimize changes upstream. """ to = payload.get("to") subject = payload.get("subject") body = payload.get("body") if not (to and subject and body): logger.error("Email task missing fields. Payload: %s", payload) return # Placeholder for real email sending logic # Implement SMTP provider call here logger.info("[Celery] Email sent | to=%s | subject=%s | body_len=%d", to, subject, len(body)) @shared_task(name="workers.send_email_fields") def send_email_fields(to: str, subject: str, body: str) -> None: """Alternate signature for convenience when calling from app code. Routes to the same implementation as send_email. """ send_email({"type": "email", "to": to, "subject": subject, "body": body})