feat: улучшения массовой обработки счетов
Some checks reported errors
continuous-integration/drone/push Build encountered an error

- Добавлено уведомление о задержке при отправке >250 счетов
- Реализовано массовое удаление счетов через /remove_account
- Исправлен flood control с задержкой 500ms между сообщениями
- Callback.answer() перенесён в начало для предотвращения timeout
- Добавлена обработка TelegramRetryAfter с повторной попыткой
This commit is contained in:
2025-11-18 16:36:30 +09:00
parent 9d59248769
commit dc402270a6

View File

@@ -438,31 +438,70 @@ async def skip_lottery_add(callback: CallbackQuery, state: FSMContext):
@admin_only
async def remove_account_command(message: Message):
"""
Деактивировать счет
Формат: /remove_account <account_number>
Деактивировать счет(а)
Формат: /remove_account <account_number1> [account_number2] [account_number3] ...
Можно указать несколько счетов через пробел для массового удаления
"""
parts = message.text.split()
if len(parts) != 2:
if len(parts) < 2:
await message.answer(
"❌ Неверный формат команды\n\n"
"Используйте: /remove_account <account_number>"
"Используйте: /remove_account <account_number1> [account_number2] ...\n\n"
"Примеры:\n"
"• /remove_account 12-34-56-78-90-12-34\n"
"• /remove_account 12-34-56-78-90-12-34 98-76-54-32-10-98-76"
)
return
account_number = parts[1]
account_numbers = parts[1:] # Все аргументы после команды
try:
async with async_session_maker() as session:
success = await AccountService.deactivate_account(session, account_number)
results = {
'success': [],
'not_found': [],
'errors': []
}
async with async_session_maker() as session:
for account_number in account_numbers:
try:
success = await AccountService.deactivate_account(session, account_number)
if success:
await message.answer(f"✅ Счет {account_number} деактивирован")
results['success'].append(account_number)
else:
await message.answer(f"❌ Счет {account_number} не найден")
results['not_found'].append(account_number)
except Exception as e:
results['errors'].append((account_number, str(e)))
# Формируем отчёт
response_parts = []
if results['success']:
response_parts.append(
f"✅ *Деактивировано счетов: {len(results['success'])}*\n"
+ "\n".join(f"• `{acc}`" for acc in results['success'])
)
if results['not_found']:
response_parts.append(
f"❌ *Не найдено счетов: {len(results['not_found'])}*\n"
+ "\n".join(f"• `{acc}`" for acc in results['not_found'])
)
if results['errors']:
response_parts.append(
f"⚠️ *Ошибки при обработке: {len(results['errors'])}*\n"
+ "\n".join(f"• `{acc}`: {err}" for acc, err in results['errors'])
)
if not response_parts:
await message.answer("Не удалось обработать ни один счет")
else:
await message.answer("\n\n".join(response_parts), parse_mode="Markdown")
except Exception as e:
await message.answer(f"Ошибка: {str(e)}")
await message.answer(f"Критическая ошибка: {str(e)}")
@router.message(Command("verify_winner"))
@@ -707,6 +746,8 @@ async def user_info_command(message: Message):
@router.callback_query(F.data == "view_my_accounts")
async def view_my_accounts_callback(callback: CallbackQuery):
"""Показать все счета пользователя"""
import asyncio
try:
async with async_session_maker() as session:
# Получаем пользователя
@@ -726,6 +767,19 @@ async def view_my_accounts_callback(callback: CallbackQuery):
await callback.answer("У вас нет счетов", show_alert=True)
return
# Отвечаем на callback сразу, чтобы не было timeout
await callback.answer("⏳ Загружаю ваши счета...")
# Если счетов много - предупреждаем о задержке
batches_count = (len(accounts) + 49) // 50 # Округление вверх
if batches_count > 5:
await callback.message.answer(
f"📊 Найдено счетов: *{len(accounts)}*\n"
f"📤 Отправка {batches_count} сообщений с задержкой (~{batches_count//2} сек)\n\n"
f"⏳ _Пожалуйста, подождите. Бот не завис._",
parse_mode="Markdown"
)
# Формируем сообщение с пагинацией (по 50 счетов на сообщение)
BATCH_SIZE = 50
for i in range(0, len(accounts), BATCH_SIZE):
@@ -736,9 +790,22 @@ async def view_my_accounts_callback(callback: CallbackQuery):
status = "" if acc.is_active else ""
text += f"{status} `{acc.account_number}`\n"
try:
await callback.message.answer(text, parse_mode="Markdown")
await callback.answer("✅ Список счетов отправлен")
# Задержка между сообщениями для избежания flood control
if i + BATCH_SIZE < len(accounts):
await asyncio.sleep(0.5) # 500ms между сообщениями
except Exception as send_error:
# Если flood control - ждём дольше
if "Flood control" in str(send_error) or "Too Many Requests" in str(send_error):
await asyncio.sleep(2)
await callback.message.answer(text, parse_mode="Markdown")
else:
raise
except Exception as e:
await callback.answer(f"❌ Ошибка: {str(e)}", show_alert=True)
# Не используем callback.answer в except - может быть timeout
try:
await callback.message.answer(f"❌ Ошибка: {str(e)}")
except:
pass # Игнорируем если не получилось отправить