PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

Problemas de conexão com SQLAlchemy e vários processos


Citando "Como eu uso engines/conexões/sessões com multiprocessamento Python, ou os.fork()?" com ênfase adicional:

O objeto SQLAlchemy Engine refere-se a um pool de conexões de conexões de banco de dados existentes. Portanto, quando esse objeto é replicado para um processo filho, o objetivo é garantir que nenhuma conexão de banco de dados seja transferida .

e

No entanto, para o caso de uma sessão ou conexão ativa de transação sendo compartilhada, não há correção automática para isso; um aplicativo precisa garantir que um novo processo filho apenas inicie novos objetos de conexão e transações, bem como objetos de sessão ORM.

O problema decorre do processo filho bifurcado que herda a sessão global ao vivo , que está segurando uma Connection . Quando alvo chama init , ele sobrescreve as referências globais para engine e sessão , diminuindo assim suas refcontas para 0 na criança, forçando-os a finalizar. Se, por exemplo, você criar outra referência para a sessão herdada no filho, por exemplo, você evita que ela seja limpa – mas não faça isso. Após main entrou e retorna aos negócios como de costume, está tentando usar a conexão agora potencialmente finalizada – ou de outra forma fora de sincronia. Por que isso causa um erro somente após uma certa quantidade de iterações, não tenho certeza.

A única maneira de lidar com essa situação usando globais da maneira que você faz é
  1. Fechar todas as sessões
  2. Chame engine.dispose()

antes de bifurcar. Isso evitará que as conexões vazem para a criança. Por exemplo:
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()

Seu segundo exemplo não aciona a finalização no filho e, portanto, parece funcionar, embora possa estar tão quebrado quanto o primeiro, pois ainda está herdando uma cópia da sessão e sua conexão definida localmente em main .