SQLAlchemy - обект, който не е маркиран като изтекъл

Имам многопоточен инструмент python3 за управление на други процеси. Използвам записи в базата данни, за да отбележа, че конкретен процес е зает в момента.

class Process(base):
    id = Column('ID', Integer, primary_key=True)
    name = Column('NAME', String(128))
    tasks = relationship('ProcessTask', back_populates="process", cascade="all, delete-orphan", passive_deletes=True)
    """ :type: list[ProcessTask] """

class ProcessTask(base):
    id = Column('ID', Integer, primary_key=True)
    process_id = Column('PROCESS_ID', Integer, ForeignKey('PROCESS.ID', ondelete='CASCADE', onupdate='CASCADE'), nullable=False)
    status = Column('STATUS', String(128), nullable=False)
    process = relationship(Process, back_populates="tasks")
    """ :type: Process """

Например, задачите имат само два възможни статуса - "работи" и "завършен"

Сблъсках се с проблем:

  • thread1 създава задача за процес
  • thread2 проверява наличността на този процес. Процесът е зает. thread2 спи, докато задачата не бъде маркирана като завършена
  • thread1 маркира задачата като завършена
  • thread2 не "вижда" промените на обекта ProcessTask и заспива завинаги

Опитах се да маркирам обекта ProcessTask като изтекъл чрез session.expire(entity) в thread2 - не работи.

какво правя грешно


Това е кодът, който използвам за създаване на фабрика за сесии:

connString = "mysql+mysqlconnector://{userName}:{userPass}@{host}:{port}/{dbName}".format(...)
self._db_engine = sqlalchemy.create_engine(connString, pool_size=100, pool_recycle=3600)
self._db_session_factory = sqlalchemy.orm.sessionmaker(bind=self.getEngine())
self._db_session = sqlalchemy.orm.scoped_session(self._db_session_factory)

Всяка нишка създава своя собствена сесия от self._db_session()


person Victor Mezrin    schedule 17.07.2015    source източник


Отговори (1)


Причината за неуспеха беше нивото на изолация на MySQL транзакциите.

Нивото на изолация по подразбиране на MySQL транзакциите е REPEATABLE READ. При първата операция за четене в транзакцията MySQL създава моментна снимка на базата данни и по време на транзакция четете от тази моментна снимка. Така че не можете да прочетете промените, направени от други нишки, докато транзакцията не приключи.

За да коригирам това поведение, трябваше да задам ниво на изолация на READ COMMITTED

https://dev.mysql.com/doc/refman/5.0/en/set-transaction.html

http://docs.sqlalchemy.org/en /relREPEATABLE READ0/orm/session_transaction.html#setting-transaction-isolation-levels

person Victor Mezrin    schedule 17.07.2015