Resqueでワーカーとキューの制御をする

非同期ワーカーが増減する非同期タスクシステムでは

  • 非同期タスク内でRDBのレコードロックをとるタスクが並列で走ってしまい、レコードロックが競合してスループットが低下したり
  • 何らかの操作を繰り返し実行すると同一のタスクが大量にキューに乗ってしまい不要な計算がなされる

などが起きます。

前者は実行時のタスク一意性を、後者はキュー内での一意性を確保することで解決でき、gemを使うと実現することができます。

resque-unique_at_runtime はresqueが提供しているhookで実装しており、タスク実行時にredisに印を記録しておき、競合するタスクが実行されそうになるとタスクを実行せず、キューに積み直します。

resque-unique_in_queue は、resque-unique_at_runtimeと同様に競合するタスクに関する印をredisに記録しておいて、対象のタスクが既にキューに積まれている場合はenqueue時に登録しない、という実装になっています。
ちなみに、hookでは実装しておらず、タスクを登録するメソッドなどをオーバーライドしまくっています。おそらく、hookで実装していない・できない理由は、before_enqueue hookは1つでも falseがあると、enqueueしないので、before_enqueueの段階ではenqueueができたのかの判断ができないから、だと思います。

これらのgemを使う時に起こるであろうトラブルは、タスクが何らかの理由によって正常に終了しなかった場合に、実行中・キュー済みを示すredisへの印の削除ができなくて、対象のタスクの実行が一切できなくなることです。

そのredisへの印には期限を設定できるので、そのようなことが発生した時にシステムが許容できる時間を設定しておき、意図した通りに動作することを入念にテストしておく必要があります。また、ワーカーがクラッシュせずに正常に終了しているか、タスクが意図しない待ち時間を持っていないかの監視も必要です。

以上。