Skip to content

Instantly share code, notes, and snippets.

@usutani
Last active January 6, 2022 12:22
Show Gist options
  • Save usutani/95cd4fd7bb575bb5c591525ec569585d to your computer and use it in GitHub Desktop.
Save usutani/95cd4fd7bb575bb5c591525ec569585d to your computer and use it in GitHub Desktop.
Rails: 10通のメールを3通毎に10秒以上時間を空けて送信する

アプリ作成

rails new try_split_bulk_mail
cd try_split_bulk_mail
bin/rails g model User email sent:boolean
bin/rails db:migrate
bin/rails g mailer User agree
bin/rails g job SendBulkAgreement
bundle add sidekiq
config/environments/development.rb
config.active_job.queue_adapter = :sidekiq
bundle add faker --group=development
bin/rails db:seed
bin/rails server
open http://localhost:3000/rails/mailers/user_mailer/agree
less -R +F log/development.log

Procfile.devの準備

brew install redis
gem install foreman
touch Procfile.dev
touch ./bin/dev
chmod +x ./bin/dev

bin/dev

ジョブの実行

bin/rails console

User.where(sent: false).count
SendBulkAgreementJob.perform_later

require 'sidekiq/api'
Sidekiq::Queue.new.size
Sidekiq::Queue.new.clear
Sidekiq::Workers.new.size

User.update_all(sent: false)
<h1>User#agree</h1>
<p>
<%= @agreement %>
</p>
User#agree
<%= @agreement %>
#!/usr/bin/env bash
foreman start -f Procfile.dev
Rails.application.configure do
# ...
config.active_job.queue_adapter = :sidekiq
end
web: bin/rails server -p 3000
redis: redis-server /usr/local/etc/redis.conf
worker: bundle exec sidekiq -q mailers
10.times do
User.create! email: Faker::Internet.email, sent: false
end
class SendBulkAgreementJob < ApplicationJob
queue_as :mailers
def perform
users = User.where(sent: false).limit(3).order(:id)
count = User.where(sent: false).count
logger.info "Target: #{users.size}/#{count}, ids: #{users.ids}"
User.transaction do
users.each do |user|
agreement = agreement_for(user: user)
UserMailer.agree(agreement).deliver_now
user.update! sent: true
end
end
if User.where(sent: false).exists?
self.class.set(wait: 10.seconds).perform_later
end
end
def agreement_for(user:)
"agreement: #{user.email}"
end
end
class UserMailer < ApplicationMailer
def agree(agreement)
@agreement = agreement
mail to: "to@example.org"
end
end
require "test_helper"
class UserMailerTest < ActionMailer::TestCase
test "agree" do
mail = UserMailer.agree(users(:one))
assert_equal "Agree", mail.subject
assert_equal ["to@example.org"], mail.to
assert_equal ["from@example.com"], mail.from
# assert_match "Hi", mail.body.encoded
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment