from __future__ import annotations import json import logging from typing import Any, Callable, Dict import pika from video_render.config import Settings logger = logging.getLogger(__name__) MessageHandler = Callable[[Dict[str, Any]], Dict[str, Any]] class RabbitMQWorker: def __init__(self, settings: Settings) -> None: print(settings) self.settings = settings self._params = pika.ConnectionParameters( host=settings.rabbitmq.host, port=settings.rabbitmq.port, credentials=pika.PlainCredentials( settings.rabbitmq.user, settings.rabbitmq.password ), heartbeat=settings.rabbitmq.heartbeat, blocked_connection_timeout=settings.rabbitmq.blocked_timeout, ) def consume_forever(self, handler: MessageHandler) -> None: while True: try: with pika.BlockingConnection(self._params) as connection: channel = connection.channel() channel.queue_declare(queue=self.settings.rabbitmq.consume_queue, durable=True) channel.queue_declare(queue=self.settings.rabbitmq.publish_queue, durable=True) channel.basic_qos(prefetch_count=self.settings.rabbitmq.prefetch_count) def _on_message(ch: pika.adapters.blocking_connection.BlockingChannel, method, properties, body): try: message = json.loads(body) except json.JSONDecodeError: logger.error("Mensagem inválida recebida: %s", body) ch.basic_ack(delivery_tag=method.delivery_tag) return logger.info("Mensagem recebida: %s", message.get("filename", "")) try: response = handler(message) except Exception: logger.exception("Erro não tratado durante o processamento") response = { "hasError": True, "error": "Erro não tratado no pipeline", "filename": message.get("filename"), "videoId": message.get("videoId"), "url": message.get("url"), "processedFiles": [], } try: payload = json.dumps(response) ch.basic_publish( exchange="", routing_key=self.settings.rabbitmq.publish_queue, body=payload, properties=pika.BasicProperties(delivery_mode=2), ) logger.info("Resposta publicada para '%s'", self.settings.rabbitmq.publish_queue) except Exception: logger.exception("Falha ao publicar a resposta na fila de upload") finally: ch.basic_ack(delivery_tag=method.delivery_tag) channel.basic_consume( queue=self.settings.rabbitmq.consume_queue, on_message_callback=_on_message, auto_ack=False, ) logger.info("Consumidor iniciado. Aguardando mensagens...") channel.start_consuming() except pika.exceptions.AMQPConnectionError: logger.exception("Conexão com RabbitMQ perdida. Tentando reconectar...") except KeyboardInterrupt: logger.info("Encerrando consumidor por interrupção do usuário.") break