首页 > 解决方案 > 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              |

标签: postgresqlsqlalchemytimeoutlockingkill-process

解决方案


我建议您将参数设置为postgresql.conf(那么它对整个 PostgreSQL 服务器有效)或 with ALTER DATABASE(那么它仅对与该数据库的新连接有效)。

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

SELECT current_setting('statement_timeout');

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


推荐阅读