sqlalchemy, когда объект становится "непостоянным" - PullRequest
0 голосов
/ 04 августа 2020

У меня есть функция с полу-продолжительным сеансом работы, которую я использую для группы строк базы данных ... и в определенный момент я хочу перезагрузить или "обновить sh" одну из строк, чтобы убедиться, что ни одно состояние не изменилось. большую часть времени этот код работает нормально, но время от времени я получаю эту ошибку

sqlalchemy.exc.InvalidRequestError: Instance '<Event at 0x58cb790>' is not persistent within this Session

Я читал о состоянии, но не могу понять, почему объект перестает быть постоянным? Я все еще нахожусь в сеансе, поэтому я не уверен, почему я перестал быть постоянным.

Может ли кто-нибудь объяснить, что может привести к тому, что мой объект будет «нестабильным» в сеансе? Я не делаю никаких записей в объект до этого момента.

db_event ниже - объект, который становится «непостоянным»

async def event_white_check_mark_handler(
    self: Events, ctx, channel: TextChannel, member: discord.Member, message: Message
):
    """
    This reaction is for completing an event
    """
    session = database_objects.SESSION()
    try:
        message_id = message.id
        db_event = self.get_event(session, message_id)
        if not db_event:
            return
        logger.debug(f"{member.display_name} wants to complete an event {db_event.id}")
        db_guild = await db.get_or_create(
            session, db.Guild, name=channel.guild.name, discord_id=channel.guild.id
        )
        db_member = await db.get_or_create(
            session,
            db.Member,
            name=member.name,
            discord_id=member.id,
            nick=member.display_name,
            guild_id=db_guild.discord_id,
        )
        db_scheduler_config: db.SchedulerConfig = (
            session.query(db.SchedulerConfig)
            .filter(db.SchedulerConfig.guild_id == channel.guild.id)
            .one()
        )
        # reasons to not complete the event
        if len(db_event) == 0:
            await channel.send(
                f"{member.display_name} you cannot complete an event with no one on it!"
            )
        elif (
            db_member.discord_id == db_event.creator_id
            or await db_scheduler_config.check_permission(
                ctx, db_event.event_name, member, db_scheduler_config.MODIFY
            )
        ):
            async with self.EVENT_LOCKS[db_event.id]:
                session.refresh(db_event)                ###########  <---- right here is when I get the error thrown
                db_event.status = const.COMPLETED
                session.commit()
                self.DIRTY_EVENTS.add(db_event.id)

            member_list = ",".join(
                filter(
                    lambda x: x not in const.MEMBER_FIELD_DEFAULT,
                    [str(x.mention) for x in db_event.members],
                )
            )
            await channel.send(f"Congrats on completing a event {member_list}!")
            logger.info(f"Congrats on completing a event {member_list}!")
            # await self.stop_tracking_event(db_event)
            del self.REMINDERS_BY_EVENT_ID[db_event.id]

        else:
            await channel.send(
                f"{member.display_name} you did not create this event and do not have permission to delete the event!"
            )
            logger.warning(f"{member.display_name} you did not create this event!")
    except Exception as _e:
        logger.error(format_exc())
        session.rollback()
    finally:
        database_objects.SESSION.remove()

1 Ответ

1 голос
/ 05 августа 2020

Я почти уверен, что причиной root в данном случае является состояние гонки. Использование сеанса с заданной областью в конфигурации по умолчанию управляет областью действия только на основе потока. Использование сопрограмм сверху может означать, что 2 или более в конечном итоге будут использовать один и тот же сеанс, а в случае event_white_check_mark_handler они затем участвуют в фиксации / откате и удалении сеанса из реестра сеансов с заданной областью, эффективно закрывая его и удаляя все оставшиеся экземпляры из ныне несуществующего сеанса, что делает другие сопрограммы недовольными. Аргумент. Если, с другой стороны, есть несколько путей, которые используют сеанс с ограниченной областью действия database_objects.SESSION вместо получения сеанса в качестве аргумента, определите подходящий scopefunc при создании реестра:

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...