Rails 4.2 Postgres 9.4.4 statement_timeout 不起作用

Edm*_*Lee 11 postgresql ruby-on-rails

我正在尝试设置 statement_timeout。我在database.yml文件中尝试了这样的设置

variables:
  statement_timeout: 1000
Run Code Online (Sandbox Code Playgroud)

和这个

ActiveRecord::Base.connection.execute("SET statement_timeout = 1000")
Run Code Online (Sandbox Code Playgroud)

测试过

ActiveRecord::Base.connection.execute("select pg_sleep(4)")
Run Code Online (Sandbox Code Playgroud)

而且两者都没有任何作用。

我在本地运行 postgres 10 并且 statement_timeouts 工作正常。但是在我运行 postgres 9.4.4 的服务器上,它根本没有做任何事情。

我已经检查了Postgres 的 9.4 文档,并且 statement_timeout 可用。任何人都可以透露一些信息吗?

dra*_*vic 1

我无法使用 Postgresql 9.4.26 在本地复制此问题。但分享我的尝试以及有关服务器问题的一些想法可能会很有用。这是我尝试过的(一个有用的位可能是从 Rails 验证 PG 版本的查询):

# Confirming I am executing against 9.4.x PG:

irb(main):002:0> ActiveRecord::Base.connection.execute("select version()")
   (10.8ms)  select version()
=> #<PG::Result:0x00007ff74782e060 status=PGRES_TUPLES_OK ntuples=1 nfields=1 cmd_tuples=1>
irb(main):003:0> _.first
=> {"version"=>"PostgreSQL 9.4.26 on x86_64-apple-darwin18.7.0, compiled by Apple clang version 11.0.0 (clang-1100.0.33.17), 64-bit"}


# Set timeout:

irb(main):004:0> ActiveRecord::Base.connection.execute("SET statement_timeout = 1000")
   (0.4ms)  SET statement_timeout = 1000
=> #<PG::Result:0x00007ff7720a3d88 status=PGRES_COMMAND_OK ntuples=0 nfields=0 cmd_tuples=0>


# Confirm it works - it is ~1s and also stacktrace is pretty explicit about it:

irb(main):005:0> ActiveRecord::Base.connection.execute("select pg_sleep(4)")
   (1071.2ms)  select pg_sleep(4)
.... (stacktrace hidden)
ActiveRecord::StatementInvalid (PG::QueryCanceled: ERROR:  canceling statement due to statement timeout)
: select pg_sleep(4)
Run Code Online (Sandbox Code Playgroud)

这是要尝试的

由于该问题仅发生在服务器上,并且statement_timeout适用于其他次要版本和本地,因此想到的一件事是缺乏statement_timeout从尝试更新的位置进行更新的权限。也许用于建立数据库连接的rails pg登录不允许更新该设置。最好的方法是通过服务器上的 Rails 控制台进行验证:

irb(main):004:0> ActiveRecord::Base.connection.execute("SET statement_timeout = 1000")
irb(main):004:0> irb(main):003:0> ActiveRecord::Base.connection.execute("show statement_timeout").first
   (0.2ms)  show statement_timeout
=> {"statement_timeout"=>"1s"}
Run Code Online (Sandbox Code Playgroud)

或者,可以直接通过 psql 控制台进行检查(某些部署也允许这样做):

psql myserveruser # if this was heroku's pg: heroku pg:psql

postgres=# set statement_timeout = 1000;
SET
postgres=# select pg_sleep(4);
ERROR:  canceling statement due to statement timeout
Time: 1068.067 ms (00:01.068)
Run Code Online (Sandbox Code Playgroud)

其他要记住的事情(取自https://dba.stackexchange.com/a/83035/90903):

statements_timeout 的工作方式是,当服务器收到来自客户端的新命令时,时间开始计时...

如果一个函数执行 SET statements_timeout = 100; 它只会在客户端发出下一个命令时开始生效。