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
します。
gem 'aws-sdk'
gem 'fake_sqs'
gem 'shoryuken'
$ bundle install
#設置
まずshoryuken用の設定ファイルを設置します。
おおむねShoryukenのGitHubリポジトリにあるサンプルを流用したものですが、
今回はFakeSQSを使うので、エンドポイントはそれ用になってます。
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に置いておきましょう。
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を書きます。
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::Worker
は perform_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_at
や perform_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