From ded5d2eb0010f09019c06bd699788ab96219a472 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9D=D0=B8=D0=BA=D0=B8=D1=82=D0=B0=20=D0=A0=D0=BE=D1=85?= =?UTF-8?q?=D0=BB=D0=B8=D0=BD?= Date: Wed, 5 Feb 2025 14:32:29 +0300 Subject: [PATCH] =?UTF-8?q?=D0=A4=D0=B8=D0=BD=D0=B0=D0=BB=D1=8C=D0=BD?= =?UTF-8?q?=D1=8B=D0=B9=20=D1=84=D0=B8=D0=BA=D1=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/crud/message.py | 10 +++++----- src/app/models/models.py | 13 ++++++------- src/bot/ratelimiter.py | 26 ++++++++++++++++++-------- 3 files changed, 29 insertions(+), 20 deletions(-) diff --git a/src/app/crud/message.py b/src/app/crud/message.py index 86a6db4..0470f19 100644 --- a/src/app/crud/message.py +++ b/src/app/crud/message.py @@ -1,13 +1,13 @@ from typing import Dict, TypeVar +from sqlalchemy import not_, select +from sqlalchemy.ext.asyncio import AsyncSession + from app.crud.base import CRUDBase from app.models.models import (Group, Message, MessageGroupAssociation, MessageStatus) from app.schemas.message import MessageCreate -from sqlalchemy import not_, select -from sqlalchemy.ext.asyncio import AsyncSession - ModelType = TypeVar('ModelType') @@ -58,11 +58,11 @@ async def get_unsent_messages(self, session: AsyncSession) -> ModelType: async def get_message_statuses( self, session: AsyncSession, - message_id: int + message_id: int, ) -> Dict[int, MessageStatus]: """Get statuses.""" statuses = await session.execute( - select(MessageStatus).where(MessageStatus.message_id == message_id) + select(MessageStatus).where(MessageStatus.message_id == message_id,) ) return {s.user_id: s for s in statuses.scalars().all()} diff --git a/src/app/models/models.py b/src/app/models/models.py index bdac63b..fa870cb 100644 --- a/src/app/models/models.py +++ b/src/app/models/models.py @@ -1,9 +1,6 @@ import pathlib from datetime import datetime -from app.core.db import Base -from app.models.constants import LENGTH_32, LENGTH_64, LENGTH_1000 - from sqlalchemy import ( BigInteger, Boolean, @@ -15,6 +12,9 @@ String) from sqlalchemy.orm import relationship +from app.core.db import Base +from app.models.constants import LENGTH_32, LENGTH_64, LENGTH_1000 + class MessageGroupAssociation(Base): """Model for many-to-many relation between messages and groups.""" @@ -57,7 +57,7 @@ class UserTG(Base): message_statuses = relationship( 'MessageStatus', bacl_populates='user', - lazy='joined' + lazy='joined', ) __table_args__ = ( @@ -103,7 +103,7 @@ class Message(Base): message_statuses = relationship( 'MessageStatus', bacl_populates='message', - lazy='joined' + lazy='joined', ) # Связь с группами groups = relationship( @@ -134,8 +134,7 @@ class MessageStatus(Base): message_id = Column(ForeignKey('message.id')) user_id = Column(ForeignKey('user_tg.id')) - status = Column(Enum('pending', 'sent', 'failed'), default='pending') - error_reason = Column(String, nullable=True) + status = Column(Enum('pending', 'sent'), default='pending') message = relationship( 'Message', diff --git a/src/bot/ratelimiter.py b/src/bot/ratelimiter.py index 3a5d981..43d513b 100644 --- a/src/bot/ratelimiter.py +++ b/src/bot/ratelimiter.py @@ -98,7 +98,9 @@ async def send_message(context: ContextTypes.DEFAULT_TYPE) -> None: # noqa: C90 if message.is_send: return - existing_statuses = crud_message.get_message_statuses(session, message_id) + existing_statuses = crud_message.get_message_statuses( + session, message_id + ) users_to_notify = set() groups = message.groups if groups: @@ -130,7 +132,7 @@ async def send_message(context: ContextTypes.DEFAULT_TYPE) -> None: # noqa: C90 MessageStatus( message_id=message.id, user_id=user_id, - status='pending' + status='pending', ) for user_id in users_to_notify - existing_statuses.keys() ] @@ -143,7 +145,6 @@ async def send_message(context: ContextTypes.DEFAULT_TYPE) -> None: # noqa: C90 try: await send_message_to_user(context, user_id, message) status.status = 'sent' - status.error_reason = None update_data = { 'is_send': True, 'sended_at': datetime.now(), @@ -157,18 +158,27 @@ async def send_message(context: ContextTypes.DEFAULT_TYPE) -> None: # noqa: C90 pydantic_scheme_obj=MessageUpdate(**update_data), session=session, ) + session.delete(status) except (BadRequest, Forbidden) as e: #Если указан неверный tg_id, или пользователь удалил аккаунт, - #или пользователь удалил бота + #или пользователь удалил бота. error_msg = str(e) logging.error( - f'Отправка сообщения отменена из-за ошибки {error_msg}' + f'Отправка сообщения отменена из-за ошибки {error_msg}', ) session.delete(status) except Exception as e: - error_msg = str(e) - status.status = 'failed' - status.error_reason = error_msg + #Повторная отправка в случае сетевых ошибок. + await asyncio.sleep(10) + context.job_queue.run_once( + send_message, + when=10, + data={ + 'message_id': message_id, + 'user_id': user_id + }, + name=f'retry_send_mes_{message_id}' + ) await session.commit()