В моем веб-приложении некоторые запросы postgres sql требуют времени для выполнения. Я хочу установить тайм-аут оператора только для их части.
Одна часть запросов должна быть отменена по таймауту, но другая должна работать без каких-либо ограничений.
В postgres существует функция statement_timeout.
Как обернуть запрос SqlAlchemy с помощью statement_timeout функция?
Как это:
SET statement_timeout TO 1000; -- timeout for one second
<sqlalchemy generated query>;
RESET statement_timeout; -- reset
Идеальный способ для меня установить тайм-аут для такого запроса:
users = session.query(User).timeout(0.5).all()
SqlAlchemy должен: 1) установить тайм-аут запроса 2) выполнить запрос и вернуть результат 3) сбросить таймаут оператора для текущего сеанса
Может быть другой способ установить тайм-аут для выполнения запроса?
ОБНОВЛЕНИЕ 1. Мое решение
Мое решение - это настраиваемый прокси-сервер подключения (протестирован с помощью psycopg2 == 2.4 и SQLAlchemy == 0.6.6):
from sqlalchemy.interfaces import ConnectionProxy
class TimeOutProxy(ConnectionProxy):
def cursor_execute(self, execute, cursor, statement, parameters, context, executemany):
timeout = context.execution_options.get('timeout', None)
if timeout:
c = cursor._parent.cursor()
c.execute('SET statement_timeout TO %d;' % int(timeout * 1000))
c.close()
return execute(cursor, statement, parameters, context)
engine = create_engine(URL, proxy=TimeOutProxy(), pool_size=1, max_overflow=0)
Это решение без сброса statement_timeout, потому что каждый запрос SqlAlchemy выполняется в изолированной транзакции и statement_timeout определено внутри текущей транзакции.
Пример использования (тайм-аут в секундах):
Session.query(Author).execution_options(timeout=0.001).all()
Session.bind.execute(text('select * from author;') \
.execution_options(timeout=0.001)) \
.fetchall()