2015-04-14 8 views
14

Eksperymentowaliśmy z obsługą rozłączeń sqlalchemy i jej integracją z ORM. Przestudiowaliśmy dokumentację i wydaje nam się, że poradą jest złapać wyjątek rozłączenia, wydać rollback() i ponowić próbę kodu.Lepsze podejście do obsługi rozłączeń sqlalchemy

np

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 

śledzę uzasadnienie - trzeba cofnąć żadnych czynnych transakcji i odtworzyć je w celu zapewnienia spójnego uporządkowanie swoich działań.

ALE - to oznacza dużo dodatkowego kodu dodanego do każdej funkcji, która chce pracować z danymi. Ponadto w przypadku SELECT nie modyfikujemy danych, a koncepcja wycofywania/ponownej prośby jest nie tylko nieestetyczna, ale stanowi naruszenie zasady DRY (nie powtarzaj się).

Zastanawiam się, czy inni nie mieliby nic przeciwko dzieleniu się tym, jak radzą sobie z rozłączeniami z sqlalchemy.

FYI: używamy SQLAlchemy 0.9.8 i PostgreSQL 9.2.9

+1

Obecnie używamy [Pesymistycznego Disconnect Handling] (http://docs.sqlalchemy.org/en/latest/core/pooling.html#disconnect-handling-pictimistic) z * pewnym * sukcesem do złagodzenia 'MySQL ma odszedł ". Wciąż widzimy jeden przypadek w produkcji, ale nie możemy wyjść z tej sytuacji, a transakcja nie może zostać wycofana i utknie. Choć może to mieć coś wspólnego z tym, że dołączamy do dwóch transakcji (ZODB i SQL) i nie używamy [Dwufazowych zatwierdzeń] (http://docs.sqlalchemy.org/en/latest/orm/ session_transaction.html # enabled-dwufazowy-commit) yet. –

+0

W PostgreSQL po prostu nie mieliśmy jeszcze żadnych rozłączeń, więc nie mamy doświadczenia. –

+0

Więc - zdecydowałeś się zaakceptować logikę try/catch/retry? Mamy kilkadziesiąt funkcji zapytań w naszej klasie ORM i zarządzamy kilkoma klasami. To naprawdę się sumuje. BTW - nie mieliśmy żadnych problemów z ponownym uruchomieniem PostgreSa do niedawna, kiedy zabójca o imieniu RHEL zabił długo działającego poczmistrza. Nagle uświadomiłem sobie, że musimy z tego wyjść z wdziękiem. – user590028

Odpowiedz

6

Sposób Chciałbym podejść to miejsce cały mój kod bazy danych w lambda lub zamknięcia, a które przechodzą do funkcji pomocniczych, które obsłuży przechwycenie wyjątku rozłączenia i ponowienie próby.

Więc z Twojego przykładu:

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 

Można uczynić to bardziej wyszukane przez przepuszczenie wartość logiczną do run_query obsłużyć przypadek, gdy robisz tylko do odczytu, dlatego chcemy, aby ponowić próbę bez wycofywania.

Pomaga to w spełnieniu zasady DRY, ponieważ cały nieprzyjemny kod płyty kotła do zarządzania ponownymi próbami i wycofywaniem jest umieszczany w jednym miejscu.

+0

To jest doskonałe rozwiązanie! Dziękuję za udostępnienie. – user590028

+0

To jest dobre rozwiązanie, ale teraz zajmuję się dokumentami SQL Alchemy, aby sprawdzić, czy można je zastosować do każdego zapytania w sposób automatyczny, zamiast przekazywać go do klasy run_query. – Mark