2015-04-14 2 views
14

Мы экспериментировали с обработкой разъединений sqlalchemy и тем, как он интегрируется с ORM. Мы изучили документы, и совет, похоже, заключается в том, чтобы уловить исключение разъединения, выдать rollback() и повторить код.Улучшенный подход к обработке отказов sqlalchemy

например:

import sqlalchemy as SA 

retry = 2 
while retry: 
    retry -= 1 
    try: 
     for name in session.query(Names): 
      print name 
     break 
    except SA.exc.DBAPIError as exc: 
     if retry and exc.connection_invalidated: 
      session.rollback() 
     else: 
      raise 

Я следую за обоснование - вы должны откатить все активные операции и воспроизводить их, чтобы обеспечить последовательный порядок ваших действий.

НО - это означает, что добавляется много дополнительного кода для каждой функции, которая хочет работать с данными. Кроме того, в случае SELECT мы не модифицируем данные, и концепция отката/повторного запроса не только неприглядная, но и нарушает принцип DRY (не повторяйте себя).

Мне было интересно, будут ли другие люди разделять, как они обрабатывают разъединения с помощью sqlalchemy.

FYI: мы используем SQLAlchemy 0.9.8 и 9.2.9 Postgres

+1

В настоящее время мы используем [Пессимистичную обработку разъединения] (http://docs.sqlalchemy.org/en/latest/core/pooling.html#disconnect-handling-pessimistic) с * некоторым * успехом для смягчения 'MySQL имеет ушел ». Мы по-прежнему видим один случай в производстве, хотя мы не можем, по-видимому, восстанавливаться после этой ситуации, и транзакция не может быть отменена и застревает. Хотя это может быть связано с тем, что мы соединяем две транзакции (ZODB и SQL) и не используем [двухфазные коммиты] (http://docs.sqlalchemy.org/en/latest/orm/ session_transaction.html # enable-two-phase-commit). –

+0

С PostgreSQL у нас просто не было никаких отключений, но нет опыта. –

+0

Итак, вы решили принять логику try/catch/retry? У нас есть десятки функций запроса в нашем классе ORM, и мы управляем несколькими десятками классов. Это действительно добавляет. BTW - у нас не было никаких проблем с перезапуском Postgres до недавнего времени, когда RHEL oom-killer убил длинного постмастера. Внезапно осознав, что нам нужно оправиться от этого изящно. – user590028

ответ

6

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

Так с вашим примером:

import sqlalchemy as SA 

def main(): 
    def query(): 
     for name in session.query(Names): 
      print name 

    run_query(query) 

def run_query(f, attempts=2): 
    while attempts > 0: 
     attempts -= 1 
     try: 
      return f() # "break" if query was successful and return any results 
     except SA.exc.DBAPIError as exc: 
      if attempts > 0 and exc.connection_invalidated: 
       session.rollback() 
      else: 
       raise 

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

Это поможет вам выполнить принцип СУХОЙ, так как весь уродливый код котельной для управления повторами + откаты устанавливается в одном месте.

+0

Это отличное решение! Спасибо, что поделился. – user590028

+0

Это хорошее решение, но теперь я просматриваю документы SQL Alchemy, чтобы узнать, можно ли это применить к каждому запросу автоматически, а не передавать его в run_query. – Mark

Смежные вопросы