我一直在挖掘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
答案 0 :(得分:30)
我们遇到了同样的问题,并进行了非常彻底的调查。我们得出结论,在我们的例子中,这个错误是由Rack::Timeout
引起的,它偶尔会在新语句创建之后但在Rails端更新计数器之前中断代码执行。然后,下一个准备好的语句尝试使用相同的名称(例如a494
),并发生冲突。
我认为Rails没有正确实现预准备语句。他们应该使用GUID,而不是使用增加的计数器(a001
,a002
,...)。这样,上述竞争条件不会成为问题。
我们没有找到解决方法。提高应用程序的性能并增加Rack::Timeout
的窗口,使这个问题几乎绝迹,但它仍然不时发生。
答案 1 :(得分:4)
这通常不是Postgres问题,而是像Unicorn这样的共享数据库连接的问题:
答案 2 :(得分:1)
这是我对Heroku的解决方案,不幸的是它有点参与其中。但是,从好的方面来说,当这个错误开始发生时,你不需要忍受100个错误通知。所需要的只是app / dyno重新启动。
该过程的基本概要是,当我们检测到ActiveRecord::StatementInvalid
异常时,如果错误消息描述包含单词' prepared statement',我们运行heroku restart
命令使用Heroku的platform-api
宝石。
platform-api
gem放入Gemfile中,然后运行bundle install
heroku config:set HEROKU_API_KEY=whatever-the-value-is
。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
那就是它。希望这会有所帮助。