백그라운드에서 환영 메시지 전송 스크립트

안녕하세요,

대규모 사용자 기반을 대상으로 환영 메시지를 백그라운드 프로세스로 보내고자 합니다. 구체적으로 다음과 같은 작업을 원합니다:

  • 메시지 생성
  • 사용자 대기열 등록
  • 전체 목록이 완료될 때까지 각 사용자에게 메시지를 1초에 1건씩 순차적으로 전송
  • 최근 로그인/방문 순서대로 전송을 정리

이 작업을 수행하는 방법에 대한 아이디어나, 이를 위한 스크립트를 작성해 주실 수 있는 분이 계신가요?

ask.discourse.org에서 좋은 출발점을 레일스 스크립트로 제시했습니다:

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 먼저 정말 멋진 닉네임이시네요… 하지만 그 답변은 더 멋집니다! 정말로 우리가 하려는 방향과 정확히 일치합니다. 좀 더 자세히 설명드리겠습니다.

우리는 350만 명의 사용자를 보유하고 있습니다. 이들에게 한꺼번에 보내는 계획은 없으며, 이 스크립트를 1만 명씩 배치별로 실행한 후 며칠간 중단하고 활동 수준을 확인한 뒤 이메일 평판을 점검하고, 다시 시작하는 식으로 진행하고자 합니다.

또한 'system’이 아닌 프로필이 있는 관리자 계정으로 이 메일을 보내고 싶습니다. 가능한가요?

다시 한번 감사드립니다. 정말 정말 큰 도움이 됩니다.

네, 스크립트에서 system을 원하는 사용자 이름으로 교체하면 됩니다.
죄송합니다. 코드를 대충 훑어봤는데 교체할 system이 없네요. 그래서 다른 방법으로 처리해야 합니다.

스크립트가 백그라운드에서 실행될 수 있도록 screen이나 tmux 같은 세션 관리자를 사용하는 것이 좋습니다.

원할 때 스크립트를 중지하고 나중에 사용자가 중지했던 지점부터 다시 시작할 수 있는 기능도 필요할 것 같습니다.

저는 프로그래머가 아니므로(즉, hello world를 출력하는 정도를 제외하고는…), 이 기능을 올바르게 설정하는 방법과 수백만 명의 사용자에게 안전하게 전송하는 방법을 조언하는 것은 다른 분들에게 맡기겠습니다. :smile:

@Canapin 모두 합리적인 의견이며, 감사합니다. 네, 시스템이 처리할 레코드 수를 카운트하는 방식으로 제한을 두면, 기본적으로 시스템이 스스로 중단되도록 만들 수 있을 것 같습니다. 다른 옵션들에 대해서는 이해했습니다.

이 작업을 더 자동화하는 방법(예: 1만 명 사용자를 배치 단위로 실행)에 대해 다른 아이디어가 있으신 분이 있다면 알려주시면 좋겠습니다.

맞아요. 만약 제가 이런 스크립트를 만들게 된다면, 스크립트가 서버 재시작이나 크래시 등으로 인해 강제 종료되는 경우를 대비해 마지막 사용자부터 다시 시작할 수 있도록 설정할 거예요.

발신자 사용자명이 포함된 업데이트된 스크립트입니다:

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 님께 보너스입니다. 내일 이 작업을 실행할 가능성이 높으며, 추가 조정이 필요한 경우 이곳에 업데이트를 게시하겠습니다…

참조: @Abdelrahman_MoHamed

아마도 이 줄을 수정해야 할 것입니다:

제 마지막 답변에는 필요한 변경 사항이 이미 포함되어 있습니다.

여기서 또 다른 질문이 있습니다. 스크립트가 현재 처리 과정의 어디까지 진행되었는지 추적하는 방법에 대해 아시는 분이 계신가요? 예를 들어, 이메일 10,000개를 발송하고 중단한 후 다시 시작할 때, 어느 레코드부터 시작해야 하는지 어떻게 알 수 있을까요?