新規サービスの立ち上げでメールの非同期実行処理を実装するのに、delayed_jobを使う。
まだユーザーも多くないし、実装やお金の面でもとりあえず低コスト。
AWSのElasticBeanstalkでAmazonLinux2のマルチDokckerプラットフォームでの実装の備忘録。
前提
- docker for mac でrailsアプリケーションを動作させていること。
- アプリケーションのコンテナ名を
web
とし、docker-compose run --rm web
のエイリアスをdcrw
として登録していること。(コマンドで使っているので読み替えて下さい。)
delayed_jobの基本的な実装
gem 'delayed_job_active_record'
gem 'devise-async' # devise のメールを非同期実行するのに必要。
docker-compose build
dcrw rails g delayed_job:active_record
dcrw rails db:migrate
bin/delayed_job
が生成される。
delayed_jobsテーブルがcreateされる。
que_adapterを設定。
config.active_job.queue_adapter = :delayed_job
コンテナとして起動。
本番用のdocker-compose.ymlもこれに準拠。
version: '3'
services: # webコンテナとworkerのコンテナを共通化。
app:
build: .
...
web:
extends:
service: app
command:
["sh", "-c", "rm -f tmp/pids/server.pid; bin/rails server -b 0.0.0.0"]
...
jobworker: # このコンテナを追加。
extends:
service: app
command: bundle exec bin/rails jobs:work
...
参考
- GitHub - collectiveidea/delayed_job: Database based asynchronous priority queue system -- Extracted from Shopify
- Railsでの非同期処理とDelayed Job | RE:ENGINES
- Railsで非同期処理の実装 - eviry tech & service blog
deviseのメール対応
これだけだとdeviseが送信するメールは非同期処理の対象にならない。
devise-async
gemをインストールし、deviseを適用しているモデルのdeviseの設定に:async
を追加。
Readmeで書かれているオプションのDevise::Async.enabled = true
だけでは非同期にならず。
devise :database_authenticatable,
:recoverable, :rememberable, :validatable,
:async # 追加
参考
- deviseで送信されるメールを非同期処理にする方法 - Qiita
- GitHub - mhfs/devise-async: Send Devise's emails in background. Supports Resque, Sidekiq, Delayed::Job and QueueClassic.
Rspecでキューイングしたメールのテストを行う
細かいことは参考のリンク先参照。
メールの本文までテストするのに、キューに入れたメールを実行する必要がある。
perform_enqueued_jobs
メソッドを使う。
RSpec.configure do |config|
config.include ActiveJob::TestHelper # 追加
end
specのメール送信処理をperform_enqueued_jobs
ブロックで囲う。
...
expect {
perform_enqueued_jobs { click_button '送信する' }
}.to change { ActionMailer::Base.deliveries.size }.by(1)
mail = ActionMailer::Base.deliveries.last
expect(mail.subject).to have_content('メールタイトル')
expect(mail.body).to have_content('メール本文…')
参考
AWSでのエラー備忘録
AWSにデプロイした際に、コンテナが落ちる現象が発生。
ログの出力を制御できていなくて時間食ったが、アプリケーションのログにエラーを吐いていた。
docker logs [docker id]
するとアプリケーションのログが見れる。
原因はDBに接続していなかったこと。
ENVの設定が必要だった。