Postgres statement_timeout 没有按预期工作

问题描述

我正在处理一个用例,在我当前的 api 应用程序中,我需要终止任何运行超过 30 秒的查询(因为我的服务器超时 30 秒,但查询继续在 Postgres 上运行)。

因此,经过一番查找后,我在 postgres 中遇到了 statement_timeout 配置。并在我的 sqlAlchemy 代码中实现它,如下所示:

@contextmanager
def db_session():
    """Executes the query."""
    import os
    from my_aws import secretsmanager
    secret_name = f'<my_secrey_key>'
    secret = secretsmanager.get_secret(secret_name)
    conn = f'{secret["dbname"]}://{secret["username"]}:{secret["password"]}@' \
           f'{secret["host"]}:{secret["port"]}/{secret["dbname"]}'
    eng = create_engine(
        conn,connect_args={'options': '-c statement_timeout=30s'})
    connection = eng.connect()
    db_session = scoped_session(sessionmaker(autocommit=False,autoflush=True,bind=eng))
    yield db_session
    db_session.close()
    connection.close()

所以我的期望是任何无法在 30 秒内完成的查询都应该超时并返回错误

所以在测试时。

我在我的一个表中放置了一个锁,通过这样做来延迟我的查询


BEGIN WORK;
LOCK TABLE <schema>.<table_name> IN ACCESS EXCLUSIVE mode;

然后我触发查询锁定表的 API 调用(从上面)。此 API 未按预期响应,因为查询无法在 30 秒内执行。

但是查询不会终止,我仍然可以看到它在 pg_stat_activity

中运行
SELECT pid,age(clock_timestamp(),query_start),usename,query
FROM pg_stat_activity
WHERE query != '<IDLE>' AND query NOT ILIKE '%pg_stat_activity%' and usename='api_user'
ORDER BY query_start desc;

所以上面的查询给出了响应:

pid |age            |usename |query                          
----|---------------|--------|-------------------------------
3334|00:05:17.962059|api_user|SELECT count(*) AS count_1 ¶FRO
1752|00:05:22.577919|api_user|COMMIT                         
1754|00:05:22.627446|api_user|COMMIT                         
3270|00:05:22.791417|api_user|SELECT count(*) AS count_1 ¶FRO
1755|00:05:23.058261|api_user|COMMIT                         
1753|00:05:23.123582|api_user|COMMIT                         
1689|00:05:24.149163|api_user|SELECT count(*) AS count_1 ¶FRO
1759|00:05:24.579171|api_user|SELECT disTINCT sum(public.dema
1760|00:05:24.631371|api_user|SELECT count(*) AS count_1 ¶FRO

如您所见,锁定表上的查询仍在等待超过 5 分钟。

我对 statement_timeout 的理解有问题吗。

仅供参考:我可以看到作为此查询的结果在 postgres 上设置了超时:

show statement_timeout;

结果:

statement_timeout|
-----------------|
30s              |

解决方法

我建议您在 postgresql.conf 中设置参数(然后它对整个 PostgreSQL 服务器有效)或使用 ALTER DATABASE 设置(那么它只对到该数据库的新连接有效)。>

如果这不起作用,则必须在某处覆盖该设置。要调试,请使用 SQLAlchemy 运行以下 SQL 语句:

SELECT current_setting('statement_timeout');

但是,当我查看您的查询时,也许一切正常:将 state 列添加到 pg_stat_activity 查询并检查 state 是否确实是 active .可能查询已经被取消,状态为 idleidle in transaction (aborted)(注意 query 显示该连接上的最后一个查询,不需要再处于活动状态)。>

,

我认为 statement_timeout 应该是一个以毫秒为单位的值。如果您真的要传递 30 秒,那可能是错误的参数值。尝试使用 30000 30 秒。

   eng = create_engine(
        conn,connect_args={'options': '-c statement_timeout=30000'})