3

私には、次のような仕事を行う約 10 人の労働者がいます。

user = User.find_or_initialize_by(email: 'some-email@address.com')

if user.new_record?
# ... some code here that does something taking around 5 seconds or so
elsif user.persisted?
# ... some code here that does something taking around 5 seconds or so
end

user.save

問題は、特定の時間に 2 人以上のワーカーがこのコードを正確な時間に実行することです。そのため、後で 2 人以上のユーザーが同じemail.

一意の電子メールは条件付きであるため、私の状況では DB 一意のインデックスを作成することはできemailません。一意の電子メールを持つべきユーザーもいれば、持たないユーザーもいます。

User私のモデルには一意性の検証があることに言及することは注目に値しますが、 と の間.find_or_initialize_by.save、ユーザー オブジェクトが既に作成されているかどうかに依存するコードがあるため、それでも役に立ちません。

悲観的ロックと楽観的ロックを試しましたが、役に立たなかった、または適切に実装していなかっただけかもしれません...これに関する提案があれば.

私が考える唯一の解決策は、これらのコード行が実行されるたびに他のスレッド (Sidekiq ジョブ) をロックすることですが、これを実装する方法がよくわかりませんし、これが提案可能なアプローチであるかどうかもわかりません。

助けていただければ幸いです。

編集

私の特定のケースでは、このジョブは上で述べたものよりも少し複雑であるため、ジョブに電子メールパラメーターを配置するのは難しいでしょう。ジョブは実際には、ジョブのセクションが上記のコードであるエクスポート スクリプトです。上記の機能を別の別のワーカーに分離することも可能だとは思いません...ジョブフロー全体がシリアルである必要があり、どの部分も並列/非同期で処理されるべきではないためです。このジョブは、最終的にマスター ジョブによって管理される別のジョブによって管理されるジョブの 1 つにすぎません。

4

3 に答える 3

2

悲観的ロックはあなたが望むものですが、存在するレコードでのみ機能しますnew_record?.DBにはまだロックするものがないため、使用できません.

于 2015-02-12T16:46:04.303 に答える
1

この問題を回避するには、別のアーキテクチャをお勧めします。

1 つのマスター Sidekiq プロセスが電子メール アドレスのリストを取得し、各電子メールに対してワーカー Sidekiq プロセスを生成するプロデューサー/ワーカー モデルはどうでしょうか? Sidekiq は、マスターとワーカーが通信するための専用キューを使用して、これを容易にします。

そうすることで、電子メールアドレスがワーカーの入力パラメーターになるため、ワーカーがお互いのデータにぶつからないことが構造上わかっています。

于 2015-02-16T13:17:51.980 に答える