[deploy] Optimization:Break Send User Digest Emails in Single Jobs (#10043)
This commit is contained in:
parent
161ed7d55e
commit
cd1db855b6
8 changed files with 92 additions and 64 deletions
|
|
@ -8,19 +8,8 @@ class EmailDigest
|
|||
end
|
||||
|
||||
def send_periodic_digest_email
|
||||
@users.find_each do |user|
|
||||
user_email_heuristic = EmailLogic.new(user).analyze
|
||||
next unless user_email_heuristic.should_receive_email?
|
||||
|
||||
articles = user_email_heuristic.articles_to_send
|
||||
begin
|
||||
next unless user.email_digest_periodic?
|
||||
|
||||
DigestMailer.with(user: user, articles: articles).digest_email.deliver_now
|
||||
rescue StandardError => e
|
||||
Honeybadger.context({ user_id: user.id, article_ids: articles.map(&:id) })
|
||||
Honeybadger.notify(e)
|
||||
end
|
||||
@users.ids.each do |user_id|
|
||||
Email::SendUserDigestWorker.perform_async(user_id)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
11
app/workers/email/enqueue_digest_worker.rb
Normal file
11
app/workers/email/enqueue_digest_worker.rb
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
module Email
|
||||
class EnqueueDigestWorker
|
||||
include Sidekiq::Worker
|
||||
|
||||
sidekiq_options queue: :medium_priority, retry: 15
|
||||
|
||||
def perform
|
||||
EmailDigest.send_periodic_digest_email
|
||||
end
|
||||
end
|
||||
end
|
||||
23
app/workers/email/send_user_digest_worker.rb
Normal file
23
app/workers/email/send_user_digest_worker.rb
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
module Email
|
||||
class SendUserDigestWorker
|
||||
include Sidekiq::Worker
|
||||
|
||||
sidekiq_options queue: :low_priority, retry: 15, lock: :until_executing
|
||||
|
||||
def perform(user_id)
|
||||
user = User.find_by(id: user_id)
|
||||
return unless user&.email_digest_periodic? && user&.registered?
|
||||
|
||||
user_email_heuristic = EmailLogic.new(user).analyze
|
||||
return unless user_email_heuristic.should_receive_email?
|
||||
|
||||
articles = user_email_heuristic.articles_to_send
|
||||
begin
|
||||
DigestMailer.with(user: user, articles: articles).digest_email.deliver_now
|
||||
rescue StandardError => e
|
||||
Honeybadger.context({ user_id: user.id, article_ids: articles.map(&:id) })
|
||||
Honeybadger.notify(e)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
class SendEmailDigestWorker
|
||||
include Sidekiq::Worker
|
||||
|
||||
sidekiq_options queue: :medium_priority, retry: 15
|
||||
|
||||
def perform
|
||||
EmailDigest.send_periodic_digest_email
|
||||
end
|
||||
end
|
||||
|
|
@ -94,7 +94,7 @@ daily_home_cache_bust:
|
|||
- "/"
|
||||
send_email_digest:
|
||||
cron: "30 11 * * 3,4,5,6" # 11:30 am UTC Wed, Thurs, Fri, Sat, Sun
|
||||
class: "SendEmailDigestWorker"
|
||||
class: "Email::EnqueueDigestWorker"
|
||||
remove_old_notifications:
|
||||
cron: "0 5 * * *" # daily at 5 am UTC
|
||||
class: "Notifications::RemoveOldNotificationsWorker"
|
||||
|
|
|
|||
|
|
@ -1,47 +1,12 @@
|
|||
require "rails_helper"
|
||||
|
||||
RSpec.describe EmailDigest, type: :labor do
|
||||
let(:user) { create(:user, email_digest_periodic: true) }
|
||||
let(:author) { create(:user) }
|
||||
|
||||
let(:mailer) { double }
|
||||
let(:message_delivery) { double }
|
||||
|
||||
before do
|
||||
allow(DigestMailer).to receive(:with).and_return(mailer)
|
||||
allow(mailer).to receive(:digest_email).and_return(message_delivery)
|
||||
allow(message_delivery).to receive(:deliver_now)
|
||||
end
|
||||
|
||||
describe "::send_digest_email" do
|
||||
context "when there's article to be sent" do
|
||||
before { user.follow(author) }
|
||||
|
||||
it "send digest email when there are at least 3 hot articles" do
|
||||
articles = create_list(:article, 3, user_id: author.id, public_reactions_count: 20, score: 20)
|
||||
|
||||
described_class.send_periodic_digest_email
|
||||
|
||||
expect(DigestMailer).to have_received(:with).with(user: user, articles: articles)
|
||||
expect(mailer).to have_received(:digest_email)
|
||||
expect(message_delivery).to have_received(:deliver_now)
|
||||
end
|
||||
|
||||
it "does not send email when user does not have email_digest_periodic" do
|
||||
articles = create_list(:article, 3, user_id: author.id, public_reactions_count: 20, score: 20)
|
||||
user.update_column(:email_digest_periodic, false)
|
||||
described_class.send_periodic_digest_email
|
||||
|
||||
expect(DigestMailer).not_to have_received(:with).with(user: user, articles: articles)
|
||||
end
|
||||
|
||||
it "does not send email when user is not registered" do
|
||||
articles = create_list(:article, 3, user_id: author.id, public_reactions_count: 20, score: 20)
|
||||
user.update_column(:registered, false)
|
||||
described_class.send_periodic_digest_email
|
||||
|
||||
expect(DigestMailer).not_to have_received(:with).with(user: user, articles: articles)
|
||||
end
|
||||
it "enqueues Email::SendUserDigestWorker" do
|
||||
user = create(:user, email_digest_periodic: true)
|
||||
allow(Email::SendUserDigestWorker).to receive(:perform_async)
|
||||
described_class.send_periodic_digest_email
|
||||
expect(Email::SendUserDigestWorker).to have_received(:perform_async).with(user.id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
require "rails_helper"
|
||||
|
||||
RSpec.describe SendEmailDigestWorker, type: :worker do
|
||||
RSpec.describe Email::EnqueueDigestWorker, type: :worker do
|
||||
let(:worker) { subject }
|
||||
|
||||
include_examples "#enqueues_on_correct_queue", "medium_priority"
|
||||
49
spec/workers/email/send_user_digest_worker_spec.rb
Normal file
49
spec/workers/email/send_user_digest_worker_spec.rb
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
require "rails_helper"
|
||||
|
||||
RSpec.describe Email::SendUserDigestWorker, type: :worker do
|
||||
let(:worker) { subject }
|
||||
let(:user) { create(:user, email_digest_periodic: true) }
|
||||
let(:author) { create(:user) }
|
||||
let(:mailer) { double }
|
||||
let(:message_delivery) { double }
|
||||
|
||||
before do
|
||||
allow(DigestMailer).to receive(:with).and_return(mailer)
|
||||
allow(mailer).to receive(:digest_email).and_return(message_delivery)
|
||||
allow(message_delivery).to receive(:deliver_now)
|
||||
end
|
||||
|
||||
include_examples "#enqueues_on_correct_queue", "low_priority"
|
||||
|
||||
describe "perform" do
|
||||
context "when there's articles to be sent" do
|
||||
before { user.follow(author) }
|
||||
|
||||
it "send digest email when there are at least 3 hot articles" do
|
||||
articles = create_list(:article, 3, user_id: author.id, public_reactions_count: 20, score: 20)
|
||||
|
||||
worker.perform(user.id)
|
||||
|
||||
expect(DigestMailer).to have_received(:with).with(user: user, articles: articles)
|
||||
expect(mailer).to have_received(:digest_email)
|
||||
expect(message_delivery).to have_received(:deliver_now)
|
||||
end
|
||||
|
||||
it "does not send email when user does not have email_digest_periodic" do
|
||||
articles = create_list(:article, 3, user_id: author.id, public_reactions_count: 20, score: 20)
|
||||
user.update_column(:email_digest_periodic, false)
|
||||
worker.perform(user.id)
|
||||
|
||||
expect(DigestMailer).not_to have_received(:with).with(user: user, articles: articles)
|
||||
end
|
||||
|
||||
it "does not send email when user is not registered" do
|
||||
articles = create_list(:article, 3, user_id: author.id, public_reactions_count: 20, score: 20)
|
||||
user.update_column(:registered, false)
|
||||
worker.perform(user.id)
|
||||
|
||||
expect(DigestMailer).not_to have_received(:with).with(user: user, articles: articles)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
Loading…
Add table
Reference in a new issue