sql >> Database >  >> RDS >> PostgreSQL

Verbindingsproblemen met SQLAlchemy en meerdere processen

Citeren "Hoe gebruik ik engines / verbindingen / sessies met Python multiprocessing, of os.fork()?" met extra nadruk:

Het SQLAlchemy Engine-object verwijst naar een verbindingspool van bestaande databaseverbindingen. Dus wanneer dit object wordt gerepliceerd naar een onderliggend proces, het doel is ervoor te zorgen dat er geen databaseverbindingen worden overgedragen .

en

Voor het geval dat een transactie-actieve sessie of verbinding wordt gedeeld, is hier echter geen automatische oplossing voor; een applicatie moet ervoor zorgen dat een nieuw onderliggend proces alleen nieuwe Connection-objecten en transacties initieert, evenals ORM Session-objecten.

Het probleem komt voort uit het gevorkte kindproces dat de live globale session overneemt , die vasthoudt aan een Connection . Wanneer target roept init . aan , het overschrijft de globale verwijzingen naar engine en session , waardoor hun refcounts bij het kind tot 0 worden verlaagd, waardoor ze gedwongen worden om af te ronden. Als je bijvoorbeeld op de een of andere manier een andere verwijzing naar de geërfde sessie in het kind creëert, voorkom je dat deze wordt opgeruimd - maar doe dat niet. Na main is toegetreden en keert terug naar de normale gang van zaken, het probeert de nu mogelijk voltooide - of anderszins niet gesynchroniseerde - verbinding te gebruiken. Waarom dit pas na een aantal iteraties een fout veroorzaakt, weet ik niet zeker.

De enige manier om met deze situatie om te gaan met globals zoals u dat doet, is door

  1. Sluit alle sessies
  2. Bel engine.dispose()

voor het vertakken. Zo voorkom je dat er verbindingen naar het kind lekken. Bijvoorbeeld:

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

Uw tweede voorbeeld activeert de finalisatie niet bij het kind, en dus lijkt het alleen maar te werken, hoewel het net zo kapot kan zijn als het eerste, omdat het nog steeds een kopie van de sessie overneemt en de verbinding die lokaal is gedefinieerd in main .




  1. Oracle:hoe groeperen op een bereik?

  2. mySQL - Een nieuwe tabel maken met gegevens en kolommen uit drie tabellen

  3. deelnemen aan door komma's gescheiden gegevenskolom

  4. Functie-geretourneerde record splitsen in meerdere kolommen