繁体   English   中英

Rails 3.2频繁postgres准备语句已经存在错误

[英]Rails 3.2 frequent postgres prepared statement already exists errors

我一直在挖堆stackoverflow试图找到其他谁得到这些准备好的语句已存在错误。

在大多数情况下,使用after / before fork正确配置unicorn可以解决这些问题。

但是在我的情况下,我们仍然会遇到错误:

ActiveRecord::StatementInvalid: PG::Error: ERROR: prepared statement "a495" already exists: INSERT INTO "user_logins" ("account_id", "created_at", "ip_address", "user_agent", "user_id") VALUES ($1, $2, $3, $4, $5) RETURNING "id"

这个错误在我们的应用程序的不同区域被抛出但似乎总是具有相同的语句号'a495'。

我们在轨道3.2.17,使用postgres,我们在heroku。

我真的不知道为什么会这样,但它现在开始更频繁地发生。

任何帮助将不胜感激。

在rails堆栈跟踪中,此错误将在.prepare调用中抛出。 我很困惑,因为它检查了语句集合中的sql密钥。 如果它不存在它准备新的....但是当试图准备它时,它抛出错误。

def prepare_statement(sql)
  sql_key = sql_key(sql)
  unless @statements.key? sql_key
    nextkey = @statements.next_key
    @connection.prepare nextkey, sql
    @statements[sql_key] = nextkey
  end
  @statements[sql_key]
end

我们遇到了同样的问题,并做了非常彻底的调查。 我们得出结论,在我们的例子中,这个错误是由Rack::Timeout引起的,在新语句已经创建之后,但在Rails端更新计数器之前,偶尔会中断代码执行。 接下来准备好的语句然后尝试使用相同的名称(例如a494 ),并发生冲突。

我的信念是Rails没有正确实现准备好的语句。 他们应该使用GUID,而不是使用增加计数器( a001a002 ,...)。 这样,上述竞争条件不会成为问题。

我们没有找到解决方法。 提高应用程序的性能,增加Rack::Timeout的窗口,使这个问题几乎绝迹,但它仍然不时发生。

这通常不是Postgres问题,而是像Unicorn这样的共享数据库连接的问题:

这是Heroku的解决方案,遗憾的是它有点参与其中。 但是,从好的方面来说,当这个错误开始发生时,你不需要忍受100个错误通知。 所需的只是app / dyno重新启动。

该过程的基本概述是,当我们检测到ActiveRecord::StatementInvalid异常,并且包含单词'prepared statement'的错误消息描述时,我们使用Heroku的platform-api gem运行heroku restart命令。

  1. platform-api gem放在Gemfile中,然后运行bundle install
  2. 将HEROKU_API_KEY设置为正确的值。 (您可以从Heroku仪表板生成密钥)。 使用heroku config:set HEROKU_API_KEY=whatever-the-value-is
  3. 将HEROKU_APP_NAME设置为正确的值。 您可以从heroku CLI获取此信息,但这只是您所谓的应用程序。
  4. 将以下内容添加到ApplicationController (/app/controllers/application_controller.rb):

...

class ApplicationController < ActionController::Base

rescue_from ActiveRecord::StatementInvalid do |exception|
  # notify your error handler, or send an email, or whatever
  # ...
  if exception.message =~ /prepared statement/
    restart_dyno
  end
end

def restart_dyno
 heroku = PlatformAPI.connect_oauth(ENV["HEROKU_API_KEY"])
 heroku.dyno.restart(ENV["HEROKU_APP_NAME"], "web")
end

end

而已。 希望这可以帮助。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM