我正在处理一个用例,在我当前的 api 应用程序中,我需要终止任何运行超过 30 秒的查询(因为我的服务器超时 30 秒,但查询继续在 Postgres 上运行)。< /p>
因此,经过一番查找后,我在 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 |
答案 0 :(得分:0)
我建议您在 postgresql.conf
中设置参数(然后它对整个 PostgreSQL 服务器有效)或使用 ALTER DATABASE
设置(那么它只对到该数据库的新连接有效)。>
如果这不起作用,则必须在某处覆盖该设置。要调试,请使用 SQLAlchemy 运行以下 SQL 语句:
SELECT current_setting('statement_timeout');
但是,当我查看您的查询时,也许一切正常:将 state
列添加到 pg_stat_activity
查询并检查 state
是否确实是 active
.可能查询已经被取消,状态为 idle
或 idle in transaction (aborted)
(注意 query
显示该连接上的最后一个查询,不需要再处于活动状态)。>
答案 1 :(得分:0)
我认为 statement_timeout 应该是一个以毫秒为单位的值。如果您真的要传递 30 秒,那可能是错误的参数值。尝试使用 30000 30 秒。
eng = create_engine(
conn,
connect_args={'options': '-c statement_timeout=30000'})