[deploy] Optimization:Break Send User Digest Emails in Single Jobs (#10043)

This commit is contained in:
Molly Struve 2020-08-28 06:37:27 -05:00 committed by GitHub
parent 161ed7d55e
commit cd1db855b6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 92 additions and 64 deletions

View file

@ -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

View 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

View 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

View file

@ -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

View file

@ -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"

View file

@ -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

View file

@ -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"

View 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