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 é
- Fechar todas as sessões
- 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 .