Как отслеживать статус actionmailer delivery_later

TL;DR

Как отслеживать сообщения в очереди, поставленные в очередь deliver_later, а также состояние их доставки?

Подробности

Я хочу отправить кучу писем асинхронно, используя deliver_later из почтовой программы. Это работает до тех пор, пока письма отправляются асинхронно, а wait: работает как положено. Все идет нормально.

Теперь я хочу предоставить некоторую информацию о статусе отправленных писем. т.е. простая строка, такая как x/y mails sent, которую я могу запросить через http или что-то еще позже (что не касается этого вопроса!). Я ожидал, что смогу легко получить доступ к очереди заданий или что-то в этом роде, где я могу затем зарегистрировать обратный вызов, как в after_action, но, по-видимому, такой вещи нет, и похоже, что мне нужно создать это вручную, используя указанные обратные вызовы, но я не могу найти ни одного ресурс даже упоминает тему «состояние доставки». Похоже, никого в мире не интересует, действительно ли отправляются deliver_latered письма, и если да, то когда. oO? Самое близкое, что я мог найти, это как проверить это для модульных тестов, но это определенно не то, что я хочу.


person ohcibi    schedule 07.11.2018    source источник


Ответы (1)


Не существует хранилища данных (помимо выбранной вами системы фоновых заданий), в котором хранится информация о завершении или состоянии вашей асинхронной доставки. Однако вы можете наблюдать за доставкой почты с помощью шаблона Rails Observer. Если вы хотите отслеживать попытки и статус доставки почты, я бы добавил в вашу базу данных таблицу для каждой доставки.

Отслеживание того, что для создания доставки был вызван метод рассыльщика:

Вы можете добавить before_action в свою почтовую программу, которая записывает запись в базу данных для вызванного почтового сообщения. Дайте вашему сообщению UUID здесь, чтобы вы могли найти его позже в базе данных. UUID может быть добавлен в заголовки ваших сообщений.

Отслеживание того, что почтовая программа доставила сообщение (позже):

Вы можете добавить наблюдателя в свою почтовую программу (или во все почтовые программы) с помощью register_observer. Класс Observer должен реализовать self.delivered_email(message), и этот метод будет вызываться после доставки электронного письма. В этот момент вы можете найти свою запись в базе данных и написать на ней метку времени, чтобы пометить ее как «отправленную».

Вот пример того, как это может выглядеть:

Это непроверенный код, он может работать не совсем так, как написано

# your mailer class
class NotifierMailer < ApplicationMailer
  after_action :record_delivery

  private

  def record_delivery
    # create an identifier for this mail message and add it 
    # to the headers of the mail message
    headers['X-Delivery-Id'] = SecureRandom.uuid
    # write a database record to track that this email is to be sent
    MailDelivery.create(uuid: headers['X-Delivery-Id'])
  end
end

# an observer class
class MailDeliveryObserver
  def self.delivered_email(message)
    delivery = MailDelivery.find_by(uuid: message.headers['X-Delivery-Id'])
    delivery&.touch(:sent_at)
  end
end

# in application.rb
# NotifierMailer can be any mailer
NotifierMailer.register_observer(MailDeliveryObserver)

Вот статья, в которой немного больше рассказывается о наблюдателях

И некоторые текущие документы Rails по наблюдателям

person jbielick    schedule 07.11.2018
comment
Какой смысл добавлять идентификатор в заголовки почты? Это просто сопоставить фактическую почту, полученную человеком, с записью в базе данных? - person ohcibi; 11.11.2018
comment
Это создает 2 записи в базе данных для каждого электронного письма, поскольку обратный вызов, по-видимому, вызывается дважды. Журнал базы данных хорош и прочее, но мне нужно логическое значение, которое сообщает мне, была ли успешно отправлена ​​почта (под этим я подразумеваю объект почты, который я хранил в памяти ранее) или нет, и все. Кажется очень сложным сделать это без всякой причины с помощью actionmailer/actionjob, если только я что-то не упустил. - person ohcibi; 11.11.2018
comment
Я имею в виду, что delivered_email — это ловушка для наблюдателя, пытающегося определить, была ли почта успешно отправлена ​​или нет, но как только вы скажете фоновому заданию сделать это (deliver_later), вы должны хранить эту единицу работы в распределенном виде. В зависимости от вашего поставщика услуг электронной почты вы также можете получать веб-перехватчики от вашего ESP при доставке почты. Я не думаю, что Amazon SES делает это. В противном случае ваше фоновое задание, которое отправляет электронное письмо, должно быть тем, которое успешно пишет, отправлено куда-то в распределенный магазин. - person jbielick; 13.11.2018
comment
Проблема заключается в том, что ActionMailer создает 2 разных объекта Mail, что приводит к двум идентификаторам доставки, хранящимся в базах данных, из которых только один будет «отправлен», поскольку другой никогда не предназначался для отправки. Поскольку заголовок удаляется при создании нового почтового объекта во второй раз, невозможно определить, какая из записей в дБ относится к тому же сообщению этого второго почтового объекта. Таким образом, ваш подход вообще не работает в отношении идентификации отправленных писем. Хорошо только сообщать, были ли электронные письма отправлены или нет, но не проверять, было ли отправлено определенное электронное письмо, которое было названо «доставлено_позже». - person ohcibi; 13.11.2018
comment
кроме того, решение несколько переработано. я вижу идентификатор работы. который генерируется activejob в логах. Я вижу выступление. а также выполненные лог-сообщения, соответствующие идентификаторам заданий. для этого должна быть возможность создать какой-нибудь простой наблюдатель в памяти вместо того, чтобы полагаться на базу данных. - person ohcibi; 13.11.2018
comment
Удачи. Похоже, ты знаешь, что делать. - person jbielick; 14.11.2018
comment
Идентификатор должен быть передан в качестве параметра для вызова метода рассылки действий, например. ActionMailer.with(delivery_id: SecureRandom.uuid). Таким образом, каждый впоследствии созданный объект Mail получит тот же идентификатор, который передается в качестве параметра. При этом сообщение может быть доставлено в delivered_mail. Если возиться с почтовым объектом, в противном случае будет сгенерировано несколько идентификаторов без возможности определить, какой из них относится к дублированному объекту. - person ohcibi; 14.11.2018
comment
› Это создает 2 записи в базе данных для каждого письма. Я переместил создание записи AR в перехватчик, и это устранило проблему с двумя записями. - person Nickolay Kondratenko; 06.11.2020