SQLAlchemy иногда ошибочно возвращает пустой результат

SQLAlchemy v1.0.6 cx_Oracle v5.2 

Некоторое время у нас возникла проблема с нашим производственным кодом и, наконец, сузилась до данных, возвращающихся из SQLAlchemy.

Выполнение одного и того же запроса несколько раз иногда возвращает пустой результат. В некоторых условиях мы можем заставить его возвращать пустой результат каждый раз, когда выполняется код. Это несмотря на то, что данные в базе данных не изменились вообще и что чистые SQL-версии одного и того же запроса, запущенные непосредственно на cx_Oracle, всегда возвращают правильный результат.

Вот декларативный код для SQLAlchemy:

 class Database: def __init__(self, service_name, database, username, password): """ service_name (str): The service name as defined in tnsnames.ora. database (str): The database within the chosen service. """ self.engine = create_engine( r'oracle+cx_oracle://{username}:{password}@{service_name}'.format(username=username, password=password, service_name=service_name), case_sensitive=False) self.session_maker = sessionmaker(bind=self.engine, autoflush=False, autocommit=False) # Database name must be injected into every table definition; this is why tables must be procedurally generated. self.Base = declarative_base() # base class for all database tables self.build_tables(database) def make_session(self): """Create a read-only session for the database.""" def readonly_abort(): raise Exception('writing is prohibited; db is read-only') session = self.session_maker() session.flush = readonly_abort return session def build_tables(self, database): class Lot(self.Base): __tablename__ = 'lot' __table_args__ = {'schema': database} lot_key = Column(Integer, primary_key=True) lot_id = Column(String, name='lot_id') self.lot = Lot 

И вот тестовый код:

 def sqlalchemy_test(): db = dp_orm.Database(service_name, database) session = db.make_session() cursor = session.query(db.lot) results = cursor.first() if results is None: raise Exception def cx_oracle_test(): import cx_Oracle import set_environment_variables conn = cx_Oracle.Connection(username, password, service_name) cursor = conn.cursor() c = cursor.execute('SELECT * FROM {}.lot WHERE rownum <= 1'.format(database)) results = list(c) if len(results) != 1: raise Exception 

Первая функция sqlalchemy_test будет ошибочной примерно в 50% случаев. Вторая функция cx_oracle_test еще не ошиблась. Теперь вот что интересно: проблема исчезает, если мы вводим паузу в течение нескольких секунд между cursor = session.query(db.lot) и results = cursor.first() . Так что это похоже на какой-то вопрос времени.

Вы знаете, что здесь происходит?

EDIT: Я упростил код, необходимый для создания ошибки. Вот:

 from sqlalchemy import create_engine, Column, Integer, String from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import sessionmaker # Fix environment variables import os try: del os.environ['ORACLE_HOME'] except KeyError: pass os.environ['TNS_ADMIN'] = r'C:\product\11.1.0\client_1\network\admin' os.environ['PATH'] = r'C:\product\11.1.0\client_1\BIN;' + os.environ['PATH'] engine = create_engine(r'oracle+cx_oracle://{username}:{password}@{service_name}'.format(username='USER', password='PASSWORD', service_name='SERVICE')) session_maker = sessionmaker(bind=engine) base_class = declarative_base() class Lot(base_class): __tablename__ = 'lot' __table_args__ = {'schema': 'SCHEMA_NAME'} lot_key = Column(Integer, primary_key=True) lot_id = Column(String) session = session_maker() cursor = session.query(Lot) result = cursor.first() if result is None: raise Exception