簡體   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