diff --git a/app/labor/email_digest.rb b/app/labor/email_digest.rb index e821f9776..ad6f0a47b 100644 --- a/app/labor/email_digest.rb +++ b/app/labor/email_digest.rb @@ -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 diff --git a/app/workers/email/enqueue_digest_worker.rb b/app/workers/email/enqueue_digest_worker.rb new file mode 100644 index 000000000..dd296e94b --- /dev/null +++ b/app/workers/email/enqueue_digest_worker.rb @@ -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 diff --git a/app/workers/email/send_user_digest_worker.rb b/app/workers/email/send_user_digest_worker.rb new file mode 100644 index 000000000..e972cb6b1 --- /dev/null +++ b/app/workers/email/send_user_digest_worker.rb @@ -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 diff --git a/app/workers/send_email_digest_worker.rb b/app/workers/send_email_digest_worker.rb deleted file mode 100644 index ba7413499..000000000 --- a/app/workers/send_email_digest_worker.rb +++ /dev/null @@ -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 diff --git a/config/schedule.yml b/config/schedule.yml index 7f1c3316e..9af38e281 100644 --- a/config/schedule.yml +++ b/config/schedule.yml @@ -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" diff --git a/spec/labor/email_digest_spec.rb b/spec/labor/email_digest_spec.rb index dd49df813..9967c2d31 100644 --- a/spec/labor/email_digest_spec.rb +++ b/spec/labor/email_digest_spec.rb @@ -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 diff --git a/spec/workers/send_email_digest_worker_spec.rb b/spec/workers/email/enqueue_digest_worker_spec.rb similarity index 85% rename from spec/workers/send_email_digest_worker_spec.rb rename to spec/workers/email/enqueue_digest_worker_spec.rb index df1ad77f5..5fd337ca6 100644 --- a/spec/workers/send_email_digest_worker_spec.rb +++ b/spec/workers/email/enqueue_digest_worker_spec.rb @@ -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" diff --git a/spec/workers/email/send_user_digest_worker_spec.rb b/spec/workers/email/send_user_digest_worker_spec.rb new file mode 100644 index 000000000..bfef8863b --- /dev/null +++ b/spec/workers/email/send_user_digest_worker_spec.rb @@ -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