Неподтвержденные транзакции в Plone + SqlAlchemy + MySql

У нас есть гибридное веб-приложение, интегрирующее базу данных MySql с Plone (последнее обновление было до Plone 4.0), использующее коллективные группы.tin, коллективные.lead и SqlAlchemy.

Хорошо, я знаю, что коллективный. Никогда не был выпущен, а коллективный. Был заменен; Однако все работает (почти) идеально, так как несколько лет.

Недавно мы испытали очень странное поведение и ищем помощи, чтобы понять это.

Среди прочего, у нас есть 2 типа контента Plone, скажем, A и B, определенные путем создания подклассов colleg.tin и соответствующих таблиц innodb MySql; строки B имеют внешний ключ к A.

За 15-20 минут 2 разных пользователя создали 3 объекта A и около 10-20 объектов B, которые не были привязаны к MySql, но были проиндексированы Plone; запросы, которые я выполнил с помощью клиента MySql из оболочки linux, не смогли найти эти строки A (не искали строки B); однако запросы, выполняемые через веб-приложение (стек вышеупомянутых компонентов) этими двумя пользователями, а также другими пользователями, иногда все еще находили и правильно визуализировали некоторые из этих трех объектов.

Только после того, как я перезапустил экземпляр Zope, можно было возобновить нормальную активность из веб-интерфейса Plone; 3 В базе данных MySql все еще отсутствовали строки A и много строк B, но счетчик автоинкрементов показал ожидаемый прирост; Мне пришлось удалить 3 недействительных мозга для объектов A из индекса Plone (не беспокоился за объекты B).

Любое предложение о возможных причинах и о том, как исследовать проблему?

1 ответ

У нас была точно такая же проблема с sqlalchemy 0.4; сеанс будет не синхронизирован с фактическим содержимым базы данных. В нашем случае проблема была несколько замаскирована, потому что пользователи были отправлены в определенные бэкэнды в кластере через сходство сеансов. Если близость терялась, сообщения внезапно исчезали. Точные детали немного туманны, потому что я не могу найти правильную (древнюю) историю изменений исправления, которое я на месте.

Из контекста я могу сказать, что карта идентификации сеанса не позволяет сеансу запрашивать базу данных для объектов, которые он извлекал ранее. Таким образом, он не увидит изменений, внесенных в эти объекты в разных сеансах.

Исправить это позвонить .expire_all() в сеансе после каждого коммита или отката; SQLAlchemy 0.5 и выше делает это автоматически (autoexpire=True на сессии, теперь называется expire_on_commit Я верю), но для 0.4 вам нужно зарегистрировать SessionExtension сделать это для вас.

К счастью для вас, мы также используем collective.lead для этого проекта, так что мое исправление - это ваше исправление:

# The identity map should be flushed on commit.
# SQLAlchemy 0.5 does this properly, but in 0.4 we need to do this via
# a SesssionExtension.

from sqlalchemy import __version__
if __version__[:3] == '0.4':
    from sqlalchemy.orm.session import SessionExtension

    class ExpireAllSessionExtension(SessionExtension):
        def after_commit(self, session):
            """Expire the identity-map on commit"""
            session.expire_all()

        def after_rollback(self, session):
            """Expire the identity-map on rollback"""
            session.expire_all()

    def installExtension():
        # Patch collective.lead.database to let us install the extension
        # on the session created there.
        from collective.lead.database import Database
        old_session = Database.session.fget
        def session(self):
            session = old_session(self)
            if session.extension is None:
                session.extension = ExpireAllSessionExtension()
            return session
        Database.session = property(session)
else:
    def installExtension():
        pass

При определении сопоставителя вы устанавливаете это расширение с помощью:

from .sessionexpiration import installExtension

# Ensure that sessions get properly expired on commit and rollback.
installExtension()
Другие вопросы по тегам