import asyncio import json from flask import current_app from app.models.users import Users import aio_pika import telebot import pika import backend_bot from config import RABBITMQ_LOGIN, RABBITMQ_PASS, RABBITMQ_HOST, RABBITMQ_QUEUE, RABBITMQ_URL_FULL # Semaphore for rate limiting rate_limit_semaphore = asyncio.Semaphore(25) def rabbitmq_connection(): credentials = pika.PlainCredentials(RABBITMQ_LOGIN, RABBITMQ_PASS) parameters = pika.ConnectionParameters( host=RABBITMQ_HOST, credentials=credentials, heartbeat=600, blocked_connection_timeout=300 ) connection = pika.BlockingConnection(parameters) channel = connection.channel() channel.queue_declare(queue=RABBITMQ_QUEUE, durable=True) return connection, channel def send_to_queue(message): connection, channel = rabbitmq_connection() channel.basic_publish( exchange='', routing_key=RABBITMQ_QUEUE, body=json.dumps(message), properties=pika.BasicProperties( delivery_mode=2, )) connection.close() async def consume_from_queue(): while True: try: connection = await aio_pika.connect_robust(RABBITMQ_URL_FULL) async with connection: channel = await connection.channel() queue = await channel.declare_queue(RABBITMQ_QUEUE, durable=True) async for message in queue: async with message.process(): try: data = json.loads(message.body.decode('utf-8')) chat_id = data["chat_id"] message_text = data["message"] await send_notification_message(chat_id, message_text) except (json.JSONDecodeError, KeyError) as e: telebot.logger.error(f"Error processing message: {e}") except Exception as e: telebot.logger.error(f"Error sending message: {e}") except aio_pika.exceptions.AMQPError as e: telebot.logger.error(f"RabbitMQ error: {e}") except Exception as e: telebot.logger.error(f"Critical error: {e}") finally: await asyncio.sleep(5) # async def send_message(chat_id, message, is_notification=False): # try: # if is_notification: # await rate_limit_semaphore.acquire() # await asyncio.to_thread(backend_bot.bot.send_message, chat_id, message, parse_mode='HTML') # formatted_message = message.replace('\n', ' ').replace('\r', '') # Добавляем форматирование сообщения # telebot.logger.info(f'Send notification to {chat_id} from RabbitMQ [{formatted_message}]') # Добавляем логирование # except telebot.apihelper.ApiTelegramException as e: # if "429" in str(e): # await asyncio.sleep(1) # await send_message(chat_id, message, is_notification) # else: # telebot.logger.error(f"Failed to send message: {e}") # except Exception as e: # telebot.logger.error(f"Unexpected error: {e}") # finally: # if is_notification: # rate_limit_semaphore.release() async def send_message(chat_id, message, is_notification=False): telegram_id = "unknown" try: if is_notification: await rate_limit_semaphore.acquire() # Получение telegram_id через app_context def get_user(): with current_app.app_context(): user = Users.query.get(chat_id) return user.telegram_id if user else "unknown" telegram_id = await asyncio.to_thread(get_user) # Отправка сообщения await asyncio.to_thread(backend_bot.bot.send_message, chat_id, message, parse_mode='HTML') # Форматирование и лог formatted_message = message.replace('\n', ' ').replace('\r', '') telebot.logger.info(f'Send notification to {telegram_id} ({chat_id}) from RabbitMQ [{formatted_message}]') except telebot.apihelper.ApiTelegramException as e: if "429" in str(e): await asyncio.sleep(1) await send_message(chat_id, message, is_notification) else: telebot.logger.error(f"Failed to send message to {telegram_id} ({chat_id}): {e}") except Exception as e: telebot.logger.error(f"Unexpected error sending message to {telegram_id} ({chat_id}): {e}") finally: if is_notification: rate_limit_semaphore.release() async def send_notification_message(chat_id, message): await send_message(chat_id, message, is_notification=True)