PostgreSQL
 sql >> Baza danych >  >> RDS >> PostgreSQL

Problemy z połączeniem z SQLAlchemy i wieloma procesami

Cytując "Jak korzystać z silników / połączeń / sesji z wieloprocesorowością Pythona lub os.fork()?" z dodatkowym naciskiem:

Obiekt SQLAlchemy Engine odwołuje się do puli połączeń istniejących połączeń z bazą danych. Więc kiedy ten obiekt jest replikowany do procesu podrzędnego, celem jest zapewnienie, że żadne połączenia z bazą danych nie zostaną przeniesione .

i

Jednak w przypadku współdzielenia sesji aktywnej w ramach transakcji lub połączenia, nie ma na to automatycznej naprawy; aplikacja musi zapewnić, że nowy proces potomny inicjuje tylko nowe obiekty i transakcje połączenia, a także obiekty sesji ORM.

Problem wynika z rozwidlonego procesu potomnego dziedziczącego globalną sesję na żywo , który utrzymuje Połączenie . Kiedy cel wywołuje init , nadpisuje globalne odniesienia do silnika i sesja , zmniejszając w ten sposób ich refcounts do 0 u dziecka, zmuszając je do sfinalizowania. Jeśli na przykład w ten czy inny sposób utworzysz inne odniesienie do odziedziczonej sesji w dziecku, zapobiegniesz jej wyczyszczeniu – ale nie rób tego. Po głównym dołączył i wraca do pracy jak zwykle, próbuje użyć teraz potencjalnie sfinalizowanego – lub w inny sposób niezsynchronizowanego – połączenia. Nie jestem pewien, dlaczego powoduje to błąd dopiero po kilku iteracjach.

Jedynym sposobem poradzenia sobie z tą sytuacją przy użyciu globalnych sposobów jest

  1. Zamknij wszystkie sesje
  2. Wywołaj engine.dispose()

przed rozwidleniem. Zapobiegnie to wyciekaniu połączeń do dziecka. Na przykład:

def main():
    global session
    init()
    try:
        dummy = Dummy(value=1)
        session.add(dummy)
        session.commit()
        dummy_id = dummy.id
        # Return the Connection to the pool
        session.close()
        # Dispose of it!
        engine.dispose()
        # ...or call your cleanup() function, which does the same
        p = multiprocessing.Process(target=target, args=(dummy_id,))
        p.start()
        p.join()
        # Start a new session
        session = Session()
        dummy = session.query(Dummy).get(dummy_id)
        assert dummy.value == 2
    finally:
        cleanup()

Twój drugi przykład nie wyzwala finalizacji u dziecka, więc tylko wydaje się działać, chociaż może być tak samo uszkodzony jak pierwszy, ponieważ nadal dziedziczy kopię sesji i jej połączenie zdefiniowane lokalnie w main .




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Co powoduje, że More nie jest rozpoznawany... błąd podczas uruchamiania Postgresql 11 na komputerze z systemem Windows?

  2. Postgresql Aktualny znacznik czasu w aktualizacji

  3. Nie można odszyfrować za pomocą pgcrypto z AES-256-CBC, ale AES-128-CBC jest OK

  4. Połączenie odrzucone (PGError) (postgresql i rails)

  5. Zwróć wartości kolumn sprzed UPDATE, używając tylko SQL