简体   繁体   English

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

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

I've been digging around stackoverflow trying to find others who get these prepared statements already exists errors. 我一直在挖堆stackoverflow试图找到其他谁得到这些准备好的语句已存在错误。

In most cases configuring unicorn properly with the after/before fork resolves these issues. 在大多数情况下,使用after / before fork正确配置unicorn可以解决这些问题。

However in my case we are still getting errors as such: 但是在我的情况下,我们仍然会遇到错误:

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"

This error gets thrown in different areas in our app but always seems to have the same statement number 'a495'. 这个错误在我们的应用程序的不同区域被抛出但似乎总是具有相同的语句号'a495'。

We are on rails 3.2.17, using postgres and we are on heroku. 我们在轨道3.2.17,使用postgres,我们在heroku。

I really have no idea why this is happening, but its starting to happen more frequently now. 我真的不知道为什么会这样,但它现在开始更频繁地发生。

Any help would be greatly appreciated. 任何帮助将不胜感激。

In the rails stack trace this error is being thrown in the .prepare call. 在rails堆栈跟踪中,此错误将在.prepare调用中抛出。 I'm confused because its checking for the sql key in the statements collection. 我很困惑,因为它检查了语句集合中的sql密钥。 If it doesn't exist it prepares the new one....however when trying to prepare it, its throwing the error. 如果它不存在它准备新的....但是当试图准备它时,它抛出错误。

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

We had the same problem, and did very thorough investigation. 我们遇到了同样的问题,并做了非常彻底的调查。 We concluded that in our case, this error is caused by Rack::Timeout , that very occasionally interrupts code execution after the new statement has been already created, but before the counter is updated on Rails side. 我们得出结论,在我们的例子中,这个错误是由Rack::Timeout引起的,在新语句已经创建之后,但在Rails端更新计数器之前,偶尔会中断代码执行。 Next prepared statement then tries to use the same name (eg a494 ), and a collision occurred. 接下来准备好的语句然后尝试使用相同的名称(例如a494 ),并发生冲突。

My belief is that Rails has not implemented prepared statements correctly. 我的信念是Rails没有正确实现准备好的语句。 Instead of using the increasing counter ( a001 , a002 , ...), they should have used GUIDs. 他们应该使用GUID,而不是使用增加计数器( a001a002 ,...)。 This way, a race condition described above wouldn't be an issue. 这样,上述竞争条件不会成为问题。

We didn't find a workaround. 我们没有找到解决方法。 Improving the performance of an app, and increasing the window for Rack::Timeout , made this problem nearly extinct, but it still happens from time to time. 提高应用程序的性能,增加Rack::Timeout的窗口,使这个问题几乎绝迹,但它仍然不时发生。

This is typically not a Postgres issue, but an issue with sharing database connections in something like Unicorn: 这通常不是Postgres问题,而是像Unicorn这样的共享数据库连接的问题:

Here's my solution for Heroku, which unfortunately is a little involved. 这是Heroku的解决方案,遗憾的是它有点参与其中。 On the plus side, though, you don't need to suffer from 100's of error notifications when this error starts happening. 但是,从好的方面来说,当这个错误开始发生时,你不需要忍受100个错误通知。 All that's needed is that the app/dyno is restarted. 所需的只是app / dyno重新启动。

The basic outline of the procedure is that when we detect a ActiveRecord::StatementInvalid exception, with an error message description that contains the words 'prepared statement', we run the heroku restart command using Heroku's platform-api gem. 该过程的基本概述是,当我们检测到ActiveRecord::StatementInvalid异常,并且包含单词'prepared statement'的错误消息描述时,我们使用Heroku的platform-api gem运行heroku restart命令。

  1. Put the platform-api gem in your Gemfile, and run bundle install platform-api gem放在Gemfile中,然后运行bundle install
  2. Set the HEROKU_API_KEY to the correct value. 将HEROKU_API_KEY设置为正确的值。 (You can generate a key from your Heroku dashboard). (您可以从Heroku仪表板生成密钥)。 Use heroku config:set HEROKU_API_KEY=whatever-the-value-is . 使用heroku config:set HEROKU_API_KEY=whatever-the-value-is
  3. Set the HEROKU_APP_NAME to the correct value. 将HEROKU_APP_NAME设置为正确的值。 You can get this information from the heroku CLI, but it's just whatever you called your app. 您可以从heroku CLI获取此信息,但这只是您所谓的应用程序。
  4. Add the following to your ApplicationController (/app/controllers/application_controller.rb): 将以下内容添加到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

That's it. 而已。 Hope this helps. 希望这可以帮助。

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

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