sql >> Databáze >  >> RDS >> PostgreSQL

Problémy s připojením s SQLAlchemy a více procesy

Citace "Jak mohu používat motory / připojení / relace s multiprocesingem Pythonu nebo os.fork()?" s přidaným důrazem:

Objekt SQLAlchemy Engine odkazuje na fond připojení existujících databázových připojení. Když je tedy tento objekt replikován do podřízeného procesu, cílem je zajistit, aby nebyla přenášena žádná databázová připojení .

a

V případě sdílené relace nebo připojení aktivní v transakci však neexistuje žádná automatická oprava; aplikace musí zajistit, aby nový podřízený proces pouze inicioval nové objekty připojení a transakce, stejně jako objekty relací ORM.

Problém pramení z rozvětveného podřízeného procesu, který zdědí živou globální session , který se drží Connection . Když target volá init , přepíše globální odkazy na engine a session , čímž se sníží jejich přepočítání na 0 v dítěti, což je přinutí dokončit. Pokud například tak či onak vytvoříte další odkaz na zděděnou relaci v dítěti, zabráníte jejímu vyčištění – ale nedělejte to. Po main se připojila a vrací se do běžného provozu, pokouší se využít nyní potenciálně dokončené – nebo jinak nesynchronizované – připojení. Pokud jde o to, proč to způsobuje chybu pouze po určitém počtu iterací, nejsem si jistý.

Jediný způsob, jak tuto situaci zvládnout pomocí globals způsobem, který děláte vy, je

  1. Uzavřete všechny relace
  2. Zavolejte engine.dispose()

před rozvětvením. Tím zabráníte úniku spojů k dítěti. Například:

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()

Váš druhý příklad nespouští finalizaci v potomkovi, a tak se zdá, že funguje, i když může být stejně nefunkční jako první, protože stále zdědí kopii relace a její připojení definované lokálně v main .




  1. MariaDB LAST_INSERT_ID() Vysvětleno

  2. Jak mohu exportovat obsah tabulky oracle do souboru?

  3. Monitorování změn tabulky v Oracle

  4. Proč vůbec používat *DB.exec() nebo připravené příkazy v Golangu?