2016-12-09 18 views
4

ruby​​ 2.1.2とレール4.1.4を使用しています。私は私のデータベースの電子メール列にユニークな制約があります。一方のスレッドがユーザーを作成している競合状態があり、他方のスレッドが同時に作成しようとする競合状態がある場合、一意の例外ではないレコードが生成されます。この例外を再試行して処理しようとしていますが、再試行すると、find_or_createでSELECT中に顧客が見つかるようになります。find_or_create ActiveRecord :: RecordNotUniqueレスキューリトライが機能しない

ただし、動作していないようです。再試行がなくなり、例外が再発生します。

は、ここで私はもともと何をやっていたのです。

retries = 10 
begin 
    user = User.find_or_create_by(:email => email) 
rescue ActiveRecord::RecordNotUnique 
    retry unless (retries-=1).zero? 
    raise 
end 

私は多分、データベース接続が、それはユーザーがまだ存在しませんし、それを作成しようとし続けることを考えるのが原因SELECTクエリの結果をキャッシュしていたと思いました。私は、クエリキャッシュを無効にするModel.uncachedを使用しようとしたことを修正するには:これも動作していない

retries = 10 
begin 
    User.uncached do 
    user = User.find_or_create_by(:email => email) 
    end 
rescue ActiveRecord::RecordNotUnique 
    retry unless (retries-=1).zero? 
    raise 
end 

`

。私はこの問題を解決するために何をすべきか分かりません。再試行を増やすべきですか?再試行の間にスリープの遅延を追加しますか?クエリキャッシュをクリアする良い方法はありますか(それが問題なのですか?)

アイデアはありますか?

ありがとうございました!

+0

この問題をどのように再現していますか?本番環境やテストスイートでそれを確認できますか?バックトレースをペーストできますか? – etagwerker

答えて

0

あなたがPostgresを使用している場合は、このようなシナリオで "ON CONFLICT DO NOTHING/UPDATE"を追加するのがとても簡単なupsert(https://github.com/jesjos/active_record_upsert)宝石があります。あなたは同じアップサート呼び出しの一部と同様の操作で他のデータを追加または更新する場合は、あなたが最初のメールは、モデルの一意のキーであることを指定する必要があり

User.upsert(email: email) 

を使用してコードを置き換えることができるだろう:

class User < ActiveRecord::Base 
    upsert_keys [:email] 
end 

編集:あなたのアプローチで問題を特定するには、我々は/にCOMMITトランザクションBEGIN含め、発行されているか、SQL文を参照することができ、ログの関連セクションを投稿してみてください。

関連する問題