Debuginfo

思考とアウトプット

TheSchwartzでメール送信を外部処理する方法

最近のwebappはいかにイベントループを止めないかが重要です。非同期処理です。重い処理はjobqueueでwebappのプロセスから投げて外してあげるというのがレスポンス向上にかかせません。PerlのjobqueueにはTheshwartzやGearmanが有名どころみたいです。調べてみたところ、すぐ処理を行うならGeramanらしいですが、Gearmanも他にプロセスをあげるようなのでDBを使ってることで信頼性が高いTheSchwartzを導入することにしました。

インストール

まずはPerlモジュールをダウンロードする。

$ cpanm TheSchwartz 

次にスキーマファイルをダウンロード。

$ wget http://cpansearch.perl.org/src/SIXAPART/TheSchwartz-1.10/doc/schema.sql  

スキーマのファイルからデータベースを作成する

$ mysql -uroot -p 
mysql> create database TheSchwartz
mysql> grant all on TheSchwartz.* to <user>@localhost identified by “xxxx”;
$ mysql -u<user> -p -DTheSchwartz < ./schema.sql

JobQueueクラスを作ります。job9->sendmail($info)でジョブを投げます。

package JobQueue;
use Mouse;

use strict;
use warnings;
use TheSchwartz;

has client => (
    is => 'ro',
    isa => 'TheSchwartz',
    lazy => 1,
    builder => '_build_client',
);

sub _build_client {
    my $self = shift;
    return TheSchwartz->new(
        databases => [{
            dsn  => 'dbi:mysql:TheSchwartz',
            user => ‘<user>’,
            pass => ‘xxxx’,
        }],
        verbose => 1,
     );
}

sub sendmail {
    my ($self, $info) = @_;
    $self->client->insert(MailWorker => $info); 
}
1;

ワーカーのスクリプトは下のようになります。postfixCentOSで走っているのでMail::Mailerを使用してメール送信を行うようにしました。

#MailWorker.pl
package MailWorker;

use strict;
use warnings;
use base qw( TheSchwartz::Worker );
use Data::Dumper;
use Mail::Mailer;
use utf8;
use Encode;

sub work {
    my ($class, $job) = @_;

    print "process...\n";
    print Dumper $job->arg;
    my $info = $job->arg;

    my $subject = encode('MIME-Header-ISO_2022_JP', $info->{'title'});
    my $url = $info->{'url'};
    my $body = “....”

    my $mailer = new Mail::Mailer 'smtp', Server => 'localhost';
    $mailer->open(
        {To => $info->{'email'},
        From => ‘my@domain.com',
        Subject => $subject,
        }
    );
    print $mailer $body;
    $mailer->close;
    $job->completed();
}

package main;
use strict;
use warnings;
use TheSchwartz;

my $client = TheSchwartz->new(
    databases => [{
        dsn  => 'dbi:mysql:TheSchwartz',
        user => ‘<user>’,
        pass => ‘xxx’,
    }],
    verbose => 1, # ログを出力
);
$client->can_do('MailWorker'); 

my $interval = 10; # default is 5
$client->work($interval);

workerプロセスを起動してジョブを待ち受けます。

$ perl MailWorker.pl

下記みたいな感じでジョブを投げたらメールを送れました!^_^

my $job9 = JobQueue->new();
my $info = { email => ‘hoge@hoge.com’,,, }
$job9->sendmail($info);

Reference :