sql >> Databasteknik >  >> RDS >> PostgreSQL

Anslutningsproblem med SQLAlchemy och flera processer

Citerar "Hur använder jag motorer / anslutningar / sessioner med Python multiprocessing, eller os.fork()?" med ytterligare betoning:

SQLAlchemy Engine-objektet hänvisar till en anslutningspool med befintliga databasanslutningar. Så när det här objektet replikeras till en underordnad process är målet att säkerställa att inga databasanslutningar överförs .

och

Men för fallet med en transaktionsaktiv session eller anslutning som delas, finns det ingen automatisk fix för detta; en applikation måste säkerställa att en ny underordnad process endast initierar nya Connection-objekt och transaktioner, såväl som ORM-sessionsobjekt.

Problemet härrör från den splittrade underordnade processen som ärver den live globala sessionen , som håller fast vid en Anslutning . När mål anropar init , skriver den över de globala referenserna till motor och session , vilket minskar deras återräkningar till 0 i barnet, vilket tvingar dem att slutföra. Om du till exempel på ett eller annat sätt skapar en annan referens till den ärvda sessionen hos barnet, förhindrar du att det städas upp – men gör inte det. Efter main har gått med och återgår till verksamheten som vanligt försöker den använda den nu potentiellt slutförda – eller på annat sätt osynkroniserad – anslutning. Varför detta orsakar ett fel först efter ett antal iterationer är jag inte säker på.

Det enda sättet att hantera den här situationen med hjälp av globala som du gör är att

  1. Stäng alla sessioner
  2. Ring engine.dispose()

innan gaffel. Detta kommer att förhindra att anslutningar läcker till barnet. Till exempel:

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

Ditt andra exempel utlöser inte slutförande i barnet, så det verkar bara fungera, även om det kan vara lika trasigt som det första, eftersom det fortfarande ärver en kopia av sessionen och dess anslutning definierad lokalt i main .




  1. Postgres 9.4 jsonb-array som tabell

  2. Hur man får data om de senaste 12 månaderna i MySQL

  3. PostgreSQL:INTE IN kontra UTOM prestandaskillnad (redigerad #2)

  4. Hur man får antalet dagar i en månad i MySQL