@VladFBR

Бот не производит снятие ролей, если находится на хостинге и имеет большую базу данных. Как исправить?

import discord
import os
import json
from discord.ext import commands, tasks
from discord import app_commands
from discord.ui import Modal, TextInput, Button, View
from datetime import datetime, timedelta, timezone

intents = discord.Intents.default()
intents.messages = True
intents.message_content = True
intents.guilds = True
intents.members = True

bot = commands.Bot(command_prefix="!", intents=intents)

ADMIN_ROLES = [1280090992581546026, 1222928883251150940]
TOKEN = 'byebye'

class SubscriptionBot(commands.Bot):
    def __init__(self):
        super().__init__(command_prefix='/', intents=intents)
        self.synced = False
        self.subscriptions = self.load_subscriptions()

    def load_subscriptions(self):
        try:
            with open('subscriptions.json', 'r') as f:
                return json.load(f)
        except FileNotFoundError:
            return {}

    def save_subscriptions(self):
        with open('subscriptions.json', 'w') as f:
            json.dump(self.subscriptions, f)

    @tasks.loop(minutes=1)
    async def check_expired_subscriptions(self):
        now = datetime.now(timezone.utc).timestamp()
        for user_id, user_subs in list(self.subscriptions.items()):
            for sub in user_subs[:]:
                if sub['expiration'] <= now:
                    guild = self.guilds[0] 
                    member = guild.get_member(int(user_id))
                    role = guild.get_role(sub['role_id'])
                    
                    if member and role:
                        await member.remove_roles(role)
                    
                    user_subs.remove(sub)
                    
                    user = await self.fetch_user(int(user_id))
                    embed = discord.Embed(
                        title="Подписка истекла",
                        description=f"Ваша подписка на роль {role.name} истекла",
                        color=discord.Color.red()
                    )
                    embed.set_thumbnail(url=user.avatar.url)
                    await user.send(embed=embed)
            
            if not user_subs:
                del self.subscriptions[user_id]
        
        self.save_subscriptions()

bot = SubscriptionBot()

@bot.tree.command(name="sub", description="Выдать роль пользователю на определенное время")
@app_commands.describe(
    user="Пользователь, которому выдается роль",
    role="Роль, которую нужно выдать",
    duration="Длительность подписки (например, 30d для 30 дней, 24h для 24 часов, 60m для 60 минут)"
)
async def sub(interaction: discord.Interaction, user: discord.Member, role: discord.Role, duration: str):
  if any(role.id in ADMIN_ROLES for role in interaction.user.roles):
    duration_units = {'d': 'days', 'h': 'hours', 'm': 'minutes'}
    amount = int(duration[:-1])
    unit = duration_units.get(duration[-1])
    if not unit:
        await interaction.response.send_message("Неверный формат длительности. Используйте 'd' для дней, 'h' для часов или 'm' для минут.", ephemeral=True)
        return

    expiration_time = datetime.now(timezone.utc) + timedelta(**{unit: amount})
    expiration_timestamp = int(expiration_time.timestamp())

    await user.add_roles(role)

    user_id = str(user.id)
    if user_id not in bot.subscriptions:
        bot.subscriptions[user_id] = []
    bot.subscriptions[user_id].append({
        'role_id': role.id,
        'expiration': expiration_timestamp
    })
    bot.save_subscriptions()

    embed = discord.Embed(
        title="Подписка оформлена",
        description=f"Вы оформили подписку {role.name}. Она истечёт <t:{expiration_timestamp}:R>",
        color=discord.Color.green()
    )
    embed.set_thumbnail(url=user.avatar.url)
    await user.send(embed=embed)

    await interaction.response.send_message(f"Подписка для {user.name} на роль {role.name} успешно оформлена.", ephemeral=True)
  else:
    await interaction.response.send_message("У вас нет прав для использования этой команды.", ephemeral=True)

@bot.tree.command(name="sub_list", description="Показать список ваших активных подписок")
async def sub_list(interaction: discord.Interaction):
    user_id = str(interaction.user.id)
    if user_id not in bot.subscriptions or not bot.subscriptions[user_id]:
        await interaction.response.send_message("У вас нет активных подписок.", ephemeral=True)
        return

    embed = discord.Embed(
        title="Ваши активные подписки",
        color=discord.Color.blue()
    )
    embed.set_thumbnail(url=interaction.user.avatar.url)

    for sub in bot.subscriptions[user_id]:
        role = interaction.guild.get_role(sub['role_id'])
        if role:
            embed.add_field(
                name=role.name,
                value=f"Истекает <t:{sub['expiration']}:R>",
                inline=False
            )

    await interaction.response.send_message(embed=embed, ephemeral=True)

@bot.event
async def on_ready():
    # Первый блок on_ready
    await bot.wait_until_ready()
    if not bot.synced:
        await bot.tree.sync()
        bot.synced = True
    print(f'Подписки синхронизированы!')
    bot.check_expired_subscriptions.start()

bot.run(TOKEN)

Запуская код на ПК и имея небольшую базу данных, которую он сохраняет всё работает отлично, но когда я ставлю его на хостинг он выдаёт роли по команде, но не снимает их по истечению времени как должно быть, хотя в хранилще опечаток не имеется. В чём может быть проблема в коде или на хостинге и как собственно от неё избавится?
  • Вопрос задан
  • 58 просмотров
Решения вопроса 1
fenrir1121
@fenrir1121 Куратор тега discord.py
Начни с документации
Json это не база данных. Одновременный вызов команд его сломает. Попытки чтения и записи одновременно из нескольких корутин приводят к неопределённому поведению и гонкам. А разрастание файла будет ещё и цикл событий подвешивать.

Переписывайте используя реальную базу данных.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы