カテゴリー
CentOS6.x perl

Mojoliciousアプリを UpStart + Sarver::Starter + Starlet で運用してみる

Server::Starter + Starlet

以前はdaemontools+Starmanで起動していたのだけれど、
最近のPlack/Starletのパフォーマンス改善まとめ。最大2倍の性能向上を読んでたらStarletが使ってみたくなったのでServer::Starter+Starletを試してみることに。

コマンドラインから起動してみる。

start_server --port=3000 -- plackup -s Starlet --max-workers=5 my app.pl

start_server (pid:31803) starting now...
starting new worker 31804
Plack::Handler::Starlet: Accepting connections at http://0:3000/

これでポート3000でサーバが待ち受けています。

UpStart

CentOS6に乗り換えたし、折角なのでデーモンの管理はUpStartに乗り換えてみる。CentOS6は標準でインストールされている(というかSysVinitが置き換わった?)なので以下のコマンドが最初から使えるみたい。daemontoolsとかsupervisorとか要らなくなりそう。

  • start SEVICE_NAME
  • stop SEVICE_NAME
  • reload SEVICE_NAME
  • restart SEVICE_NAME

perlの起動方法がよく分からなかったけどStack Overflowでそれっぽい記事を発見したので参考に書いてみた。

vi /etc/init/MyApp.conf

description "MyApp"
author "clicktx<clicktx@mail.tld>"

start on runlevel [2345]
stop on runlevel [016]

chdir /home/clicktx/MyApp/Web
script
  export PATH="/home/clicktx/perl5/perlbrew/bin:/home/clicktx/perl5/perlbrew/perls/perl-5.16/bin:/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/sbin:/home/clicktx/bin:${PATH}"

  exec su -c "start_server --pid-file=/tmp/myapp.pid --status-file=/tmp/myapp.status --port=3000 -- plackup -s Starlet --max-workers=5 myapp.pl" clicktx
end script

respawn

※ exportするPATHは各自 echo $PATHで確認

サービスの起動
$ sudo start MyApp
MyApp start/running, process 32114

start は initctl start というコマンドのエイリアスのようだ。全てのジョブリストの確認は

$ sudo initctl list

とかで出来る。

余談

start_serverで起動するMojoliciousアプリケーションは他のperlスクリプトから再起動を受け付けたいので、--pid-fileと --status-file オプションを付けている(start_server --restartの場合は必須なので)

他のスクリクトから、

#!/usr/bin/env perl
system "start_server --restart --pid-file=/tmp/myapp.pid --status-file=/tmp/myapp.status";

なんて出来る。もちろんコマンドラインでも出来るけど。

あと、

start_server --port=127.0.0.1:3000 -- plackup -s Starlet myapp.pl

なんてしておくと、http://xxxx:3000 でアクセスされても表示されないみたい。

参考エントリー
カテゴリー
CentOS6.x perlモジュール インストールメモ

[Perl][CentOS6] Net::SSLeayがインストール出来ない時

openssl-develをインストールしてからインストールする。

sudo yum install openssl-devel
cpanm Net-SSLeay
カテゴリー
Mojolicious

mojoliciousでSSLページヘリダイレクトさせると無限ループしてしまう問題

問題点

この問題は Mojoliciousでhttps(SSL)専用ページとhttp専用ページの振り分けをroutesのbridgeを使って行うを実装した時に起こる問題です。

件のエントリーの実装でもスタンドアロンのサーバで公開する場合には問題にならないのですが、Nginx等のリバースプロクシの後ろにアプリケーションサーバを置いて運用する場合に問題が起きます。

通常、webサーバであるNginxとクライアントの間ではSSL通信を行い、バックエンドのアプリケーションサーバ(Starman等)とNginxの間では通常のhttpで通信すると思います。

           SSL通信
クライアント   ---   Nginx
                     |     http通信
                   Starman

この場合だと、件のエントリーの

  # SSL onry routes
  my $ssl_rotes = $routes->bridge->to(
    cb => sub{
      my $self = shift;
 
      my $req = $self->req;
      return 1 if $req->is_secure;
      
      $self->redirect_to($req->url->to_abs->scheme('https'));
      return;
    }
  );

ようにschemeで判定してhttps~にリダイレクトする場合、Nginxとアプリケーションは常にhttpで通信しているのでリダイレクトが無限ループしてしまいます。

Nginxとアプリケーション間をSSLにすればよいのですが、(アプリケーション側の)ポートを開けたり指定しなくてはならなくなったりと色々面倒なことになりそうです...。

対策

Nginxの設定でリダイレクトを使うか、SSLの場合はリンクをhttpsで指定するかしか無さそう。

例えばstartupの中で下記のようなhelperを定義して、

  # helper method
  $self->helper(
    url_for_http => sub {
      my $self = shift;      
      my $url = $self->url_for(@_)->to_abs->scheme('http');
      return $url;
    }
  );
  $self->helper(
    url_for_https => sub {
      my $self = shift;      
      my $url = $self->url_for(@_)->to_abs->scheme('https');
      return $url;
    }
  );

templateで

<%= link_to url_for_http('/') => begin %>httpを強要<% end %>
<%= link_to url_for_https('/ssl_onry') => begin %>セキュアなページへのリンク<% end %>

のように使うしか無いのかな。

カテゴリー
Mojolicious

Mojoliciousでhttps(SSL)専用ページとhttp専用ページの振り分けをroutesのbridgeを使って行う

このエントリーには問題点があります(2013/5/5追記)

webアプリを作る上でセキュアな通信を強要するページとそうではないページを振り分けるにはどうすればいいのか悩んでいたのだけど、ルーターでリダイレクトさせる方法にしてみた。

全てのページをSSLでアクセスされても速度的にとか負荷的に困るので、ある決まったrouteのみSSLでアクセスして、メインのコンテンツは通常のhttp通信(非SSL)にredirectする仕様。

必ずhttpsでアクセスするルート
  • /login
  • /join
必ずhttpでアクセスするルート
  • /
  • /entry/1
  • /entry/2
  • /entry/....
httpでもhttpsでもいいルート
  • /mypage
  • /favorite/list/1

例ではログインページや登録ページではセキュアな通信をして、トップページとエントリーページは普通のhttpで通信する。httpsでもhttpでもどちらでもいいページは最後の Any routes の所で振り分けられる。

sub startup {
  $self = shift;
....

  # Routes
  my $routes = $self->routes;

  # SSL onry routes
  my $ssl_rotes = $routes->bridge->to(
    cb => sub{
      my $self = shift;

      my $req = $self->req;
      return 1 if $req->is_secure;
      
      $self->redirect_to($req->url->to_abs->scheme('https'));
      return;
    }
  );
  # スッキリ書くならこんな感じ?
  # my $ssl_rotes = $routes->bridge->to(
  #   cb => sub{
  #     return 1 if $_[0]->req->is_secure;      
  #     $_[0]->redirect_to($_[0]->req->url->to_abs->scheme('https'));
  #     return;
  #   }
  # );
  # Not SSL routes
  my $not_ssl_routes = $routes->bridge->to(
    cb => sub{
      my $self = shift;
      
      my $url = $self->req->url;
      return 1 if $url->base->scheme eq 'http';
      
      $self->redirect_to($url->to_abs->scheme('http'));
      return;
    }
  );

  # SSL onry route
  $ssl_rotes->route('/login')->to('login#index');
  $ssl_rotes->route('/join')->to('join#index');

  # not SSL routes
  $not_ssl_routes->route('/')->to('top#index');
  $not_ssl_routes->route('/entry/:id', id => qr/\d+/)->to('entry#index', id => 1 );

  # Any Routes
  $routes->route('/:controller')->to(action => 'index');
  $routes->route('/:controller/:action')->to();
  $routes->route('/:controller/:action/:id')->to();
}

考えついたのはこんな感じのコードだけど、もっといい方法があるかもしれません。知っている方いたら教えて下さい!

カテゴリー
perlモジュール

[perl] Lingua::JA::Expand::DataSource::GoogleWebSearchっていうの書いた

手軽に関連語を取得するモジュール - ダウンロードたけし(寅年)の日記

Lingua::JA::Expand は愛用させて頂いているperl moduleですが、近年のAPI不正利用対策の影響でYahoo!APIの利用規約が変更になります。

  • 検索Web APIにて新プランをリリースしました - Yahoo! JAPAN Tech Blog
  • xデーは2013年3月31日。Yahoo!プレミアム会員だと500回/day。これではちょっとだけ少ないし...。 という事で、Lingua::JA::Expand::DataSource::xxx を書けば使えそうなので書いてみた。

  • clicktx/Lingua-JA-Expand-DataSource-GoogleWebSearch · GitHub
  • 基本的にはWeb::Scraperでレスポンスを解析しているだけ。使うには Lingua::JA::Expandを継承したMyExpandクラスを作って、datasourceメソッドをオーバーライドする。

    package MyExpand;
    
    use base qw(Lingua::JA::Expand);
    
    # method overriding.
    sub datasource {
        my $self = shift;
        $self->_class_loader( datasource => 'DataSource::GoogleWebSearch' );
    }

    問題点

    googleの規約には

    本サービスを不正に利用しないでください。たとえば、本サービスの妨害や、Google が提供するインターフェースおよび手順以外の方法による本サービスへのアクセスを試みてはなりません。

    とあります。しかし、以前の規約である利用規約のアーカイブには、

    5.3 Google が提供するインタフェース以外の手段で、本サービスのいずれにもアクセスしないこと(またはアクセスを試みないこと)に同意するものとします。ただし、Google との別個の契約において明確な許可を受けた場合は除きます。特に、ユーザーは、いかなる本サービスについても、いかなる自動化された方法(スクリプトやウェブ クローラーの利用によるものを含みます)によりアクセスせず、アクセスを試みないことに同意し、また、本サービスに関して提示されるいかなる robots.txt ファイルにおける指示に従うものとします。

    と記されていたものが削除されているので、getリクエストで(botがアクセスしても)なら良くなったとも見える。いずれにしろ解釈の違いでどっちとも取れそうな気はするけど、普通に考えればアウトかな。

    あと、とりあえずokだとしてもそこそこのリクエストでアクセス拒否されますので実用性に欠けます。

    google

    某中華製検索エンジンには利用規約にも書いていないので、使うならそっちの方がいいかもね。Web::Scraperのprocessをちょっと変えればすぐに出来るはず。

    関連リンク

  • Takeshi Miki / Lingua-JA-Expand - search.cpan.org