Edited at

[Rails] Shoryuken + FakeSQSで非同期処理

More than 3 years have passed since last update.

Railsで非同期処理っていったらDelayedJobとかResqueとかSidekiqとかいろいろありますが、

今回はShoryukenにチャレンジしてみます。

ShoryukenはAWS SQSからジョブ取り出すワーカーを簡単に作っちゃおうっていうGemなんですが、

今回は本物のSQSは貧乏なので使わずにFake SQSというSQS(っぽいもの)をローカルで立てることができるGemを使ってローカルのみで動くShoryuken Workerを書いちゃいましょう。


登場人物


  • AWS SQS: すごく安くキューが使えるニクいやつ

  • AWS-SDK: RubyからAWSを簡単に操作できるニクいやつ

  • Fake SQS: SQSっぽいものをローカルに立てられるニクいやつ

  • Shoryuken: SQSからジョブを取り出すニクいやつ


導入

あらかじめ適当なRailsプロジェクトを作っておきます。

いつも通りプロジェクトのGemfileに追記してbundle installします。


Gemfile

gem 'aws-sdk'

gem 'fake_sqs'
gem 'shoryuken'

$ bundle install


設置

まずshoryuken用の設定ファイルを設置します。

おおむねShoryukenのGitHubリポジトリにあるサンプルを流用したものですが、

今回はFakeSQSを使うので、エンドポイントはそれ用になってます。


config/shoryuken.yml


aws:
access_key_id: access key id
secret_access_key: secret access key
region: region
sqs_endpoint: http://localhost:4568
receive_message:
attribute_names:
- ApproximateReceiveCount
- SentTimestamp
concurrency: 25
delay: 25
queues:
- default

次に、FakeSQSにジョブを差し込む用のキューを作成するためのスクリプトを書きます。

initializersに置いておきましょう。


config/initializers/sqs.rb

sqs_client = Aws::SQS::Client.new(

endpoint: 'http://localhost:4568',
secret_access_key: 'secret access key',
access_key_id: 'access key id',
region: 'region'
)
sqs_client.create_queue(queue_name: 'default')

仕上げに簡単なShoryuken Workerを書きます。


app/workers/sqs_worker.rb

class SqsWorker

include Shoryuken::Worker

shoryuken_options queue: 'default', auto_delete: true, body_parser: :json

def perform(sqs_msg, body)
puts sqs_msg, body
end
end



実行

必要なファイルの設置は終わったので、実行してみましょう。

まずはFake SQS。

$ bundle exec fake_sqs

次は本命のShoryukenを動かします。

-Cで指定したコンフィグファイル、-RでRailsのコードとapp/workers以下のworkerを読み込んでくれます。

$ bundle exec shoryuken -R -C config/shoryuken.yml

動作確認してみます。

rails cからこんな感じでFake SQSのキューにメッセージを送ってみましょう。

sqs_client = Aws::SQS::Client.new(

endpoint: 'http://localhost:4568',
secret_access_key: 'secret access key',
access_key_id: 'access key id',
region: 'region'
)
queue_url = sqs_client.get_queue_url(queue_name: 'default')['queue_url']
sqs_client.send_message(queue_url: queue_url, message_body: {hoge: :fuga}.to_json)

シェルにこんな感じの出力があったら成功です。

踊りましょう。

#<Shoryuken::Message:0x007f2160e435a8>

{"hoge"=>"fuga"}


perform_asyncする

Shoryuken::Workerperform_async メソッドで設定したキューにジョブを入れられます。

SqsWorker.perform_async(hoge: 'fuga')

といった具合です。

イカしてますね。

その他の使い方はこちらに。

https://github.com/phstc/shoryuken/wiki/Sending-a-message


FakeSQSで動かす

FakeSQSを使っているといろいろと問題があって上手く動かないので Aws::SQS::Client を使って直接メッセージを入れていたんですが、此度対処法を調べました。

下にあるエラーが出るのであれば、 initializers/sqs.rb 辺りに追記すると恐らく動きます。

どうもFakeSQSの仕様上、 perform_atperform_in は動かないみたいですが。

FakeSQSを使わないとき(本物のSQSを使う時とか)には対処コードが読み込まれないように注意してください。


Aws::Errors::MissingRegionError が出るとき

Shoryukenが上手くconfigを読めていないっぽい。

Shoryuken::EnvironmentLoader.load に設定を読ませると回避できました。

config_file = Rails.root.join('config', 'shoryuken.yml')

config = YAML.load(ERB.new(IO.read(config_file).result)).deep_symbolize_keys
Shoryuken::EnvironmentLoader.load(config)

参考: https://github.com/phstc/shoryuken/issues/68


Aws::Errors::ChecksumError が出るとき

aws-sdk v2.3以降で出るっぽい。

MD5を検証しているメソッドを叩き潰したら回避できました。

class Aws::Plugins::SQSMd5s::Handler

def validate_attributes(*args)
true
end
end

参考: https://github.com/iain/fake_sqs/issues/40