Help us understand the problem. What is going on with this article?

shoryukenの諸動作

More than 3 years have passed since last update.

Railsの非同期処理として、今までDelayedJobで運用していたものを、shoryukenに載せ替えたので、使い勝手をまとめます。
最初はsidekiqにしようと思っていたので、ちょいちょいsidekiqとの比較が出てきます。

メッセージのポーリング

メッセージのポーリング間隔はshoryuken.ymlで設定します。ちなみに、ここのポーリング間隔と、エンキューされるキューの合計数でSQSの料金が変わってくるみたい。ただ、SQSの料金プランによると100万件ごとに課金されるので、そこまでシビアに考える必要はなさそうだけれど。

shoryuken.yml
:delay: 25  # 単位は秒

以下のようにしておくと、リクエストを投げ続けてくれる。

shoryuken.yml
:delay: 0

ちなみに、このdelay値は、エンキューされてから、処理が開始されるまでの時間にモロに響いてくるので、もし「即時送らねば!」という処理を積みたい場合は、金額を試算した上で短くすることをおすすめします。

リトライ

リトライ機構

sidekiqではsidekiq.ymlに

sidekiq.yml
:retry: 25

と書いておけば、リトライ回数を設定できたが、shoryukenではそういうわけにはいかない。

重要となるのは、SQSのVisibility Timeoutです。
SQSに蓄積されたメッセージは、蓄積直後、どのshoryukenワーカーからも見える状態になっています。
そして、1つのワーカーがメッセージを受信した時点で、そのメッセージは見えなくなります(処理中という扱い)。
しかし、処理が一定時間終わらなければ、SQS側では「なにか失敗したかな?」ということで、メッセージを再びどのワーカーからも見える状態に戻します。この処理中扱いにしてくれる時間が、Visibility Timeoutです。

処理の成功・失敗にかかわらず、Visibility Timeoutが来てしまえば、再びメッセージが受信可能な状態になり、いずれかのワーカーに処理される可能性があります。

成功時

処理の成功・失敗にかかわらず、Visibility Timeoutが来ればメッセージが受信可能状態になる、と言いましたが、shoryukenにはauto_delete というオプションがあり、これが成功時にメッセージを削除してくれます。
なので、auto_deleteを有効にしておけば、成功したメッセージが再び処理されることはなくなります。

sample_worker.rb
class SampleWorker
  include Shoryuken:Worker
  shoryuken_options queue: "default", auto_delete: true

  def perform(sqs_msg, body)
    # something
  end
end

auto_delete: false はどんなときに使うのか、イマイチ想像できないですね……。

リトライ回数指定

というわけで、失敗時には、メッセージが削除されず、Visibility Timeoutが来た後再びどこかのワーカーが受信し、処理します。
では、このリトライ回数に上限は指定できるのでしょうか?

これは、shoryuken側の設定ではなく、SQS側で設定します。
SQSにはDead Letter Queueというものが設定できます。これは、「n回受信(ワーカーがメッセージを取得)したらDead Letter Queueとして指定された別のキューにメッセージを移す」というものです。
Dead Letter Queueに入ってしまえば、キューが変わるので、shoryukenのワーカーからはまったく見えなくなります。

なので、リトライ回数の指定は、Dead Letter Queueの受信回数条件で設定することが可能です。

shoryuken.yml
:queues:
  - asumibot-patient-queue

みたいなキュー設定をしたら、AWS SQSにDead Letter Queueを作ります。
新しく、asumibot-dead-letter-queue というキューを作り、asumibot-patient-queue の設定画面で、

スクリーンショット 2016-02-08 14.40.33.png

こんな設定をしてやれば、20回目の受信で、Dead Letter Queueに移してくれて、それ以降リトライされなくなります。

リトライしたくない場合は、ここのMaximum Receives を1にしておけば良さそう。

リトライ間隔

リトライ間隔は以下のように、ワーカーごとに設定できます。

sample_worker.rb
class CopyCheckWorker
  include Shoryuken::Worker
  shoryuken_options queue: "default", auto_delete: true, retry_intervals: [60, 120, 180] # 単位は秒

この状態だと、1回目のリトライが60秒後、2回目が120秒後となります。
ただし、retry_intervals で設定した値を超えた回数リトライが発生した場合は、通常通りVisibility Timeoutに依存したリトライとなります。
また、ここで指定するのはあくまで間隔だけで、リトライ上限回数はDead Letter Queueでしか設定できませんでした。

※ただし、retry_intervals はこの時間後にメッセージが見えるようになるだけで、厳密にはポーリング間隔との兼ね合いがあり、ポーリング間隔が長い場合は即時受信してくれるわけではない。

Visibility Timeoutの変更

Visibility Timeoutがかなり重要なことはご理解いただけたと思います。
このVisibility Timeout、デフォルトでは30秒となっています。

もし、ジョブの実行時間が30秒をオーバーしそうな場合には、Visibility Timeoutを延ばす必要がでてきます。

sample_worker.rb
class SampleWorker
  include Shoryuken::Worker
  shoryuken_options queue: "default", auto_delete: true, retry_intervals: [60, 120, 180]

  def perfom(sqs_msg, body)
    sqs_msg.visibility_timeout = 60
    # something
  end
end

スレッド

shoryukenのスレッドは、shoryuken.ymlのconcurrency で設定します。

shoryuken.yml
:concurrency: 25

キューごとのスレッド数を指定したい場合は、

shoryuken.yml
:concurrency: 25
:queues:
  - [ default, 4 ]
  - [ asumiss, 10 ]

と書いておき、合計値がconcurrency を超えないようにしておきます。
この辺はsidekiqと同じですね。

番外編:fake_sqs

ローカルで以上のようなshoryukenの動作を実現したい場合、AWS SQSではなくfake_sqs を使うという手があります(安いとはいえAWS SQSではお金かかりますからね)。
http://qiita.com/iemon7stars/items/d4efdd8872d287906d29

fake_sqsの場合、ほとんどAWS SQSと同等の動作をしてくれますが、2点重要なことがあります。

  1. メモリ上にキューが作られるので、fake_sqsを起動するたびにキューを作ってやる必要がある
  2. retry_intervalsの設定が効かない

1は、まぁ仕組み上仕方ないでしょう。
http://qiita.com/iemon7stars/items/d4efdd8872d287906d29
こちらの記事通り、どこかでキューを作ってやるしかないです。

2については、shoryukenのmiddlewareで失敗時に、sqs_message.attributes['ApproximateReceiveCount'] からattempts (失敗回数)を導き出して失敗後の処理をしていますが、fake_sqsを見る所attributesが空になっているのが原因です。
おそらく、fake_sqsではメッセージのattributesに対応していないので、ここはどうにもならないですね……。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした