Python 如何使用SQLAlchemy关闭和重新连接以避免事务超时中的空闲

Python 如何使用SQLAlchemy关闭和重新连接以避免事务超时中的空闲,python,postgresql,sqlalchemy,Python,Postgresql,Sqlalchemy,我编写了一个Python应用程序,它使用SQLAlchemy连接到Postgres DB。引擎和会话在db.py engine = create_engine(URL(**settings.DATABASE)) session = scoped_session(sessionmaker(bind=engine)) from app.db import engine, session def get_door_ids(): result = session.query(Controll

我编写了一个Python应用程序,它使用SQLAlchemy连接到Postgres DB。
引擎
会话
db.py

engine = create_engine(URL(**settings.DATABASE))
session = scoped_session(sessionmaker(bind=engine))
from app.db import engine, session

def get_door_ids():
    result = session.query(ControllerDetail.door_id).distinct().all()
    ids = [c[0] for c in result]
    return ids

def get_last_health_cd(door_id):
    result = session.query(ControllerDetail.door_health_cd).filter(ControllerDetail.door_id == door_id).order_by(ControllerDetail.etl_insert_ts.desc()).first()
    return result[0]
大多数db操作都在
service.py
中,它从
db.py

engine = create_engine(URL(**settings.DATABASE))
session = scoped_session(sessionmaker(bind=engine))
from app.db import engine, session

def get_door_ids():
    result = session.query(ControllerDetail.door_id).distinct().all()
    ids = [c[0] for c in result]
    return ids

def get_last_health_cd(door_id):
    result = session.query(ControllerDetail.door_health_cd).filter(ControllerDetail.door_id == door_id).order_by(ControllerDetail.etl_insert_ts.desc()).first()
    return result[0]
现在一切都很好,但问题是我需要每隔几分钟重复运行相同的程序。因此,我的主模块中有以下代码:

try:
    while True:
        run_task()
        time.sleep(120)
except KeyboardInterrupt:
    print('Manual break by user')
DB每分钟超时一次空闲连接。因此,每次进程休眠超过1分钟时,我都会出错

psycopg2.InternalError: terminating connection due to idle-in-transaction timeout
SSL connection has been closed unexpectedly
我想知道是否有办法在
时间之后关闭会话并重新打开它。sleep(120)
这样它就不会超时。可能在主模块中,我从
db
导入
session
作为全局变量,并以某种方式将其传递给
服务中的方法。我该怎么做?我不能从
main
导入
services
中的
session
,而不能从
db
导入,因为
main
services
导入功能
  • 增加超时时间

    create_引擎(URL(**settings.DATABASE),connect_args={'connect_timeout':10})

  • 出现错误时创建新会话
  • 您可以通过
    session.close()

  • 首先,您应该通过提交/回滚及时结束事务。会话还将隐式回滚。如果是作用域会话,将关闭该会话(并从注册表中删除该会话)。总而言之,这是一本很好的读物


    一些人可能会感到惊讶的是,
    会话
    会在您开始与数据库通信时立即启动一个新事务。然后,您的工作就是结束该交易。如果不了解
    run_task()
    的实际作用,很难说哪个部分应该处理会话的生存期,但可以肯定地说,如果任务每隔几分钟运行一次,您就不应该让事务挂起那么长时间。

    那么客户端的超时设置会覆盖服务器的设置吗?由于会话是在
    db.py
    中创建的,然后导入到其他模块中,因此无法轻松创建/关闭会话,也无法让所有方法都像以前一样使用与服务器设置相关的相同会话。您可以根据需要增加数据库由我们的DBA管理的时间。超时是他不愿改变的事情之一。为了关闭并重新连接主模块中的
    会话
    ,我必须将其作为全局文件从
    db
    导入,并将其传递给
    服务
    中的方法。我该怎么做呢?我在
    运行任务()之前创建了
    作用域会话
    ,之后将其关闭。现在,
    session
    run\u任务(session)
    的一个参数。因此,所有其他函数也将
    会话
    作为其参数。不确定将
    session
    作为这些查询函数的参数是否是常见的做法,但它在使用线程局部作用域会话时工作。行有点模糊,因为卖点之一是您不需要显式地传递会话(尽管这没有错),并且如果您的任务(或您所拥有的)由工作线程处理。使用
    作用域_会话
    可以很容易地将会话的生命周期与工作线程的生命周期联系起来。当您说您曾经在
    run_task()
    之后关闭作用域会话时,请执行循环调用
    run_task()
    它在同一个线程中实际运行的是什么?如果不是,您创建了一个会话,工作线程又创建了一个。我没有使用线程。这是一个警报引擎,需要每两分钟运行一次,并轮询数据库中的异常情况。
    run\u task
    所做的只是查询和发送电子邮件。啊,在这种情况下,您不需要一个
    scoped_session
    。只需从
    sessionmaker()
    获取一个普通的
    session
    旧实例就可以了,传递它是一个很好的模式;至少它使测试更容易,并提高了可重用性。