Citat "Hvordan bruger jeg motorer / forbindelser / sessioner med Python multiprocessing eller os.fork()?" med ekstra vægt:
SQLAlchemy Engine-objektet henviser til en forbindelsespulje af eksisterende databaseforbindelser. Så når dette objekt replikeres til en underordnet proces, er målet at sikre, at ingen databaseforbindelser overføres .
og
Men i tilfælde af, at en transaktionsaktiv session eller forbindelse deles, er der ingen automatisk løsning på dette; en applikation skal sikre, at en ny underordnet proces kun starter nye forbindelsesobjekter og -transaktioner samt ORM-sessionsobjekter.
Problemet stammer fra den forklede underordnede proces, der arver den live globale session
, som holder på en forbindelse
. Når mål
kalder init
, overskriver den de globale referencer til engine
og session
, hvilket reducerer deres gentællinger til 0 i barnet, hvilket tvinger dem til at afslutte. Hvis du for eksempel på den ene eller anden måde opretter en anden reference til den nedarvede session hos barnet, forhindrer du, at der bliver ryddet op – men det gør du ikke. Efter main
har tilsluttet sig og vender tilbage til business as usual, forsøger den at bruge den nu potentielt afsluttede – eller på anden måde ude af synkronisering – forbindelse. Hvorfor dette kun forårsager en fejl efter nogle gentagelser er jeg ikke sikker på.
Den eneste måde at håndtere denne situation ved at bruge globals, som du gør, er at
- Luk alle sessioner
- Ring til
engine.dispose()
før gaffel. Dette vil forhindre forbindelser i at lække til barnet. For eksempel:
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()
Dit andet eksempel udløser ikke færdiggørelse i barnet, og det ser derfor kun ud til at virke, selvom det måske er lige så ødelagt som det første, da det stadig arver en kopi af sessionen og dens forbindelse defineret lokalt i main .