Improve `ActionMailer::MailDeliveryJob` performance by using replica

Problem

From gitlab-com/gl-infra/scalability#1811 (comment 1332375768). Amongst the workers set to :always data consistency, ActionMailer::MailDeliveryJob is consistently in the top 5 for sum.db_main_duration_s.

MailDeliveryJob performs the mail_method which is the mailer's logic (Gitlab code) before calling the delivery_method which sends the mail. From kibana, ~20% of jobs have 0 json.db_write_count and the remainder only have 1 json.db_write_count (it shows 3 in kibana but it is a bug that !116218 (merged) fixes).

The insert is performed by SentNotification.record. An example is in https://gitlab.com/gitlab-org/gitlab/-/blob/c0c3de94829c80df91a0d5b070205a2326474334/app/mailers/emails/issues.rb#L6.

It is used in mailers as seen from a ripgrep of the project.

ee/app/mailers/emails/epics.rb
35:      @sent_notification = SentNotification.record(@epic, recipient_id, reply_key)

app/mailers/emails/reviews.rb
34:      @sent_notification = SentNotification.record(@merge_request, recipient_id, reply_key)

app/mailers/emails/service_desk.rb
55:      @sent_notification = SentNotification.record(@issue, @support_bot.id, reply_key)

app/mailers/emails/issues.rb
115:      @sent_notification = SentNotification.record(@issue, recipient_id, reply_key)

app/mailers/emails/notes.rb
82:        @sent_notification = SentNotification.record_note(@note, recipient_id, reply_key)

app/mailers/emails/merge_requests.rb
176:      @sent_notification = SentNotification.record(@merge_request, recipient_id, reply_key)

Caveat: jobs with 1-write, the write is performed within a transaction, so the performance gains would not be mind-blowing but the initial chunk of reads will be off-loaded to the replica.

Proposal

Switch ActionMailer::MailDeliveryJob data consistency to :sticky or even :delayed.

Adding data_consistency for ActionMailer::MailDeliveryJob will be done through DummyWorker which is done in sidekiq_config. This is fake news. Mail jobs passes through our middleware as a ActiveJob::QueueAdapters::SidekiqAdapter::JobWrapper. We will likely need to update the load balancing middlewares.

Edited by Sylvester Chin