LoginSignup
45
34

More than 5 years have passed since last update.

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

Last updated at Posted at 2015-11-25

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

45
34
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
45
34