Скрипт для отправки приветственного сообщения в фоновом режиме

Здравствуйте,

Меня интересует отправка приветственного сообщения нашей большой базе пользователей в фоновом режиме, для этого необходимо:

  • Создать сообщение
  • Сформировать очередь пользователей
  • Отправлять сообщение каждому пользователю по одному в секунду, пока весь список не будет обработан
  • Также хотелось бы организовать отправку по дате последнего входа/посещения

У кого-нибудь есть идеи, как это реализовать, или кто-то может написать скрипт для этого?

ask.discourse.org — хорошая отправная точка. Вот пример скрипта на Rails:

MAX_MESSAGES = 1000 # Опциональный лимит для тестирования
SECONDS_BETWEEN_MESSAGES = 3 # Интервал в 3 секунды

Rails.logger.info "Запуск скрипта массовой рассылки сообщений..."

# Определите содержимое вашего сообщения
message_title = "Добро пожаловать в наше сообщество"
message_body = "Привет! Мы очень рады видеть вас здесь. Дайте нам знать, если у вас возникнут вопросы!"

# Получите пользователей, отсортированных по последнему времени активности
users = User.where(active: true)
            .where.not(staged: true) # Исключить пользователей в режиме тестирования
            .order(last_seen_at: :desc)
            .limit(MAX_MESSAGES)

Rails.logger.info "Найдено активных пользователей для рассылки: #{users.count}."

users.each_with_index do |user, index|
  begin
    Rails.logger.info "Добавление сообщения в очередь для #{user.username} (#{index + 1}/#{users.count})..."

    PostCreator.create!(
      Discourse.system_user,
      title: message_title,
      raw: message_body,
      archetype: Archetype.private_message,
      target_usernames: user.username,
      skip_validations: true
    )

    Rails.logger.info "Сообщение успешно добавлено в очередь для #{user.username}."

    # Подождите указанный интервал перед обработкой следующего пользователя
    sleep(SECONDS_BETWEEN_MESSAGES)
  rescue => e
    Rails.logger.error "Не удалось отправить сообщение пользователю #{user.username}: #{e.message}"
  end
end

Rails.logger.info "Скрипт массовой рассылки завершен!"

Я не вносил никаких изменений, и пользователь system отправил личные сообщения всем пользователям в моем тестовом экземпляре:


Сколько у вас пользователей?

@Canapin, во-первых, какой потрясающий никнейм… но ваш ответ ещё впечатляющий! Это именно то, что мы планируем сделать. Вот немного подробнее.

У нас 3,5 миллиона пользователей. Мы не планируем отправлять сообщения всем сразу. Идея в том, чтобы запускать этот скрипт, возможно, партиями по 10 тысяч, затем делать перерыв на несколько дней, оценивать активность, проверять репутацию отправителя и затем начинать заново, и так далее.

Мы хотели бы отправлять это от имени администратора с профилем, а не от «системы». Предполагаю, это возможно?

Спасибо огромное, очень, очень полезно.

Да, просто замените system на нужное имя пользователя в скрипте.
Извините, я пробежался по коду, там нет system для замены, значит, это нужно сделать другим способом.

Скорее всего, вам стоит использовать менеджер сессий, например screen или tmux, чтобы ваш скрипт мог работать в фоновом режиме.

Я также предполагаю, что вы захотите иметь возможность останавливать скрипт по желанию и перезапускать его позже от того же пользователя, на котором он остановился.

Поскольку я не программист (имею в виду, кроме как выводить hello world…), я предоставлю другим дать советы по правильной настройке этой функции, а также безопасной рассылке миллионам пользователей :smile:

@Canapin Всё логично, спасибо. Да, я думаю, что можно просто подсчитать количество записей, через которые система должна пройти, чтобы она сама остановилась, но я понимаю и другие варианты.

Если у кого-то есть идеи, как сделать это более автоматизированным (например, запускать пакетами по 10 тысяч пользователей), буду рад услышать.

Да. Если бы я создавал такой скрипт, я бы настроил его так, чтобы можно было возобновить работу с последнего пользователя в случае, если скрипт будет принудительно остановлен (перезагрузка сервера, сбой и т. д.).

Вот обновленный скрипт с именем отправителя:

MAX_MESSAGES = 1000 # Опциональный лимит для тестирования
SECONDS_BETWEEN_MESSAGES = 3 # Интервал в 3 секунды
SENDER_USERNAME = "coco"

message_sender = User.find_by(username: SENDER_USERNAME)

if message_sender.nil?
  Rails.logger.error "Пользователь отправителя '#{message_sender_username}' не найден!"
  exit
end

Rails.logger.info "Запуск скрипта массовой рассылки сообщений..."

# Определите содержимое вашего сообщения
message_title = "Добро пожаловать в наше сообщество"
message_body = "Привет! Мы очень рады видеть вас здесь. Дайте знать, если у вас возникнут вопросы!"

# Получите пользователей, отсортированных по времени последнего посещения
users = User.where(active: true)
            .where.not(staged: true) # Исключить пользователей в стадии обработки
            .order(last_seen_at: :desc)
            .limit(MAX_MESSAGES)

Rails.logger.info "Найдено #{users.count} активных пользователей для рассылки."

users.each_with_index do |user, index|
  begin
    Rails.logger.info "Добавление сообщения в очередь для #{user.username} (#{index + 1}/#{users.count})..."

    PostCreator.create!(
      message_sender,
      title: message_title,
      raw: message_body,
      archetype: Archetype.private_message,
      target_usernames: user.username,
      skip_validations: true
    )

    Rails.logger.info "Сообщение успешно добавлено в очередь для #{user.username}."

    # Подождите указанный интервал перед обработкой следующего пользователя
    sleep(SECONDS_BETWEEN_MESSAGES)
  rescue => e
    Rails.logger.error "Не удалось отправить сообщение пользователю #{user.username}: #{e.message}"
  end
end

Rails.logger.info "Скрипт массовой рассылки сообщений завершен!"

Это бонус для @Canapin — мы, скорее всего, запустим это завтра. Если внесем дополнительные корректировки, опубликуем здесь обновления…

CC: @Abdelrahman_MoHamed

Скорее всего, вам нужно отредактировать эту строку:

В моём последнем ответе уже содержатся необходимые изменения.

Ещё один вопрос. Есть ли у кого-нибудь идея, как отслеживать, на каком этапе находится скрипт? Например, мы отправили 10 000 писем и остановились. Затем хотим продолжить с того же места. Как узнать, с какой записи нужно начать?