0

このワーカーを 10 回起動して、並行性を感じさせます。

class AnalyzerWorker
  @queue = :analyzer

  def self.perform
    loop do
      # My attempt to lock pictures from other worker instances that may
      # try to analyze the same picture (race condition)

      pic = Pic.where(locked: false).first
      pic.update_attributes locked: true 

      pic.analyze
    end
  end
end

このコードは実際にはまだ競合状態に対して脆弱です。その理由の 1 つは、ロックされていない画像を取得してから実際にロックするまでに時間のギャップがあるためだと思います。

もっと理由があるかもしれませんが、これを防ぐための強力なアプローチはありますか?

4

1 に答える 1

0

Active Record は、楽観的ロックと悲観的ロックを提供します。

楽観的ロックを使用するには、テーブルに整数型の lock_version という列が必要です。レコードが更新されるたびに、Active Record は lock_version 列をインクリメントします。現在データベースの lock_version 列にある値よりも小さい値を lock_version フィールドに指定して更新要求を行うと、更新要求は ActiveRecord::StaleObjectError で失敗します。

悲観的ロックは、基礎となるデータベースによって提供されるロック メカニズムを使用します。リレーションを構築するときにロックを使用すると、選択した行で排他ロックが取得されます。ロックを使用するリレーションは通常、デッドロック状態を防ぐためにトランザクション内にラップされます。

コードサンプルは、参照リンクで提供されています...

どちらでも動作するはずですが、それぞれ異なる実装が必要です。あなたがしていることから、競合の可能性が比較的高いため、悲観的ロックを検討します。

あなたの現在の実装は両方の混合のようなものですが、あなたが指摘したように、それは実際には問題を解決しません。あなたは自分のものを機能させることができるかもしれませんが、Active Record の実装を使用することは理にかなっています。

于 2013-09-26T05:30:42.853 に答える