2

Rails プロジェクトに mailman gem を統合しました。gmail からメールを正常に取得します。私のアプリには、メールのモデル メッセージがあります。電子メールはメッセージ モデルとして適切に保存されます。

問題は、メールが複数回保存されることがあり、パターンを認識できないことです。一部のメールは 1 回保存され、一部は 2 回保存され、一部は 3 回保存されます。

しかし、私のコードで失敗を見つけることができません。

これが私のmailman_serverスクリプトです:

スクリプト/mailman_server

#!/usr/bin/env ruby
# encoding: UTF-8
require "rubygems"
require "bundler/setup"
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'config', 'environment'))
require 'mailman'

Mailman.config.ignore_stdin = true
#Mailman.config.logger = Logger.new File.expand_path("../../log/mailman_#{Rails.env}.log", __FILE__)

if Rails.env == 'test'
  Mailman.config.maildir = File.expand_path("../../tmp/test_maildir", __FILE__)
else
  Mailman.config.logger = Logger.new File.expand_path("../../log/mailman_#{Rails.env}.log", __FILE__)
  Mailman.config.poll_interval = 15
  Mailman.config.imap = {
    server: 'imap.gmail.com',
    port: 993,  # usually 995, 993 for gmail
    ssl: true,
    username: 'my@email.com',
    password: 'my_password'
  }
end

Mailman::Application.run do
  default do
    begin
      Message.receive_message(message)
    rescue Exception => e
      Mailman.logger.error "Exception occurred while receiving message:\n#{message}"
      Mailman.logger.error [e, *e.backtrace].join("\n")
    end
  end
end

メールは Message クラス内で処理されます。

  def self.receive_message(message)
    if message.from.first == "my@email.com"
      Message.save_bcc_mail(message)
    else
      Message.save_incoming_mail(message)
    end
  end

  def self.save_incoming_mail(message)
    part_to_use = message.html_part || message.text_part || message
    if Kontakt.where(:email => message.from.first).empty?
      encoding = part_to_use.content_type_parameters['charset']
      Message.create topic: message.subject, message: part_to_use.body.decoded.force_encoding(encoding).encode('UTF-8'), communication_partner: message.from.first, inbound: true, time: message.date
    else
      encoding = part_to_use.content_type_parameters['charset']
      Message.create topic: message.subject, message: part_to_use.body.decoded.force_encoding(encoding).encode('UTF-8'), communication_partner: message.from.first, inbound: true, time: message.date, messageable_type: 'Company', messageable_id: Kontakt.where(:email => message.from.first).first.year.id
    end
  end

  def self.save_bcc_mail(message)
    part_to_use = message.html_part || message.text_part || message
    if Kontakt.where(:email => message.to.first).empty?
      encoding = part_to_use.content_type_parameters['charset']
      Message.create topic: message.subject, message: part_to_use.body.decoded.force_encoding(encoding).encode('UTF-8'), communication_partner: message.to.first, inbound: false, time: message.date
    else
      encoding = part_to_use.content_type_parameters['charset']
      Message.create topic: message.subject, message: part_to_use.body.decoded.force_encoding(encoding).encode('UTF-8'), communication_partner: message.to.first, inbound: false, time: message.date, messageable_type: 'Company', messageable_id: Kontakt.where(:email => message.to.first).first.year.id
    end
  end

このスクリプトで mailman_server をデーモン化しました:

スクリプト/mailman_daemon

#!/usr/bin/env ruby

require 'rubygems'  
require "bundler/setup"  
require 'daemons'

Daemons.run('script/mailman_server') 

capistrano でデプロイします。

これは、mailman_server の停止、開始、および再起動を担当する部分です。

スクリプト/deploy.rb

set :rails_env, "production" #added for delayed job  
after "deploy:stop",    "delayed_job:stop"
after "deploy:start",   "delayed_job:start"
after "deploy:restart", "delayed_job:restart"
after "deploy:stop",    "mailman:stop"
after "deploy:start",   "mailman:start"
after "deploy:restart", "mailman:restart"

namespace :deploy do
  desc "mailman script ausfuehrbar machen"
  task :mailman_executable, :roles => :app do
   run "chmod +x #{current_path}/script/mailman_server"
  end

  desc "mailman daemon ausfuehrbar machen"
  task :mailman_daemon_executable, :roles => :app do
   run "chmod +x #{current_path}/script/mailman_daemon"
  end
end

namespace :mailman do  
  desc "Mailman::Start"
  task :start, :roles => [:app] do
   run "cd #{current_path};RAILS_ENV=#{fetch(:rails_env)} bundle exec script/mailman_daemon start"
  end

  desc "Mailman::Stop"
  task :stop, :roles => [:app] do
   run "cd #{current_path};RAILS_ENV=#{fetch(:rails_env)} bundle exec script/mailman_daemon stop"
  end

  desc "Mailman::Restart"
  task :restart, :roles => [:app] do
   mailman.stop
   mailman.start
  end
end

展開中に mailman サーバーの複数のインスタンスがほぼ同時に開始され、各インスタンスがほぼ同時にポーリングされる可能性はありますか? 2 番目と 3 番目のインスタンスは、最初のインスタンスが電子メールを既読としてマークし、電子メールをポーリングして処理する前にプールしますか?

アップデート 30.01。

ポーリング間隔を 60 秒に設定しました。しかし、それは何も変わりません。

mailman pid ファイルが格納されているフォルダーを確認しました。mailman pid ファイルは 1 つだけです。したがって、実行中の mailman サーバーは 1 つだけです。ログファイルを確認したところ、メッセージが複数回取得されていることがわかりました。

Mailman v0.7.0 started
IMAP receiver enabled (my@email.com).
Polling enabled. Checking every 60 seconds.
Got new message from 'my.other@email.com' with subject 'Test nr 0'.
Got new message from 'my.other@email.com' with subject 'Test nr 1'.
Got new message from 'my.other@email.com' with subject 'test nr 2'.
Got new message from 'my.other@email.com' with subject 'test nr 2'.
Got new message from 'my.other@email.com' with subject 'test nr 3'.
Got new message from 'my.other@email.com' with subject 'test nr 4'.
Got new message from 'my.other@email.com' with subject 'test nr 4'.
Got new message from 'my.other@email.com' with subject 'test nr 4'.

私には、問題は間違いなくメールマン サーバー コードにあるように思えます。

アップデート 31.1。

私には、それは私の生産機械に関係があるようです。本番マシンとまったく同じ構成で開発中にこれをテストしている場合(今朝、ローカルデータベースをsqliteからmysqlに変更してテストしました)、重複はありません。おそらく私のコードはすべて問題ありませんが、本番マシンに問題があります。これに対する解決策を見つけられるかどうか、ホストに尋ねます。これを修正するには、Ariejan の提案に従います。

解決策: 問題が見つかりました。tmp ディレクトリがすべてのリリース間で共有されているマシンにデプロイします。mailman_daemon の pid ファイルを保存するパスを定義するのを忘れていました。そのため、/tmp/pids ディレクトリではなくスクリプト ディレクトリに保存されました。このため、新しいデプロイ後に古い mailman_daemon を停止できませんでした。それは私のメールアカウントをポーリングしていた作業中のmailman_daemonsの軍隊につながりました...これらすべてのプロセスを強制終了した後、すべてうまくいきました! もう重複はありません!

4

2 に答える 2

0

問題が見つかりました。tmp ディレクトリがすべてのリリース間で共有されているマシンにデプロイします。mailman_daemon の pid ファイルを保存するパスを定義するのを忘れていました。そのため、/tmp/pids ディレクトリではなくスクリプト ディレクトリに保存されました。このため、新しいデプロイ後に古い mailman_daemon を停止できませんでした。それは私のメールアカウントをポーリングしていた作業中のmailman_daemonsの軍隊につながりました...これらすべてのプロセスを強制終了した後、すべてうまくいきました! もう重複はありません!

于 2014-01-31T18:56:24.923 に答える