Posts categorized "Perl" Feed

Oct 03, 2015

Mojolicious で X-Forwarded-For からプロキシではなくクライアントの IP っぽいものをとってこれるプラグインを書いた。

使い方は SYNOPSIS の通り、

use Mojolicious::Lite;

plugin 'ClientIP';

get '/' => sub {
    my $c = shift;
    $c->render(text => $c->client_ip);
};

Mojolicious 的にはリモートアドレス取るとなったら $c->tx->remote_address を使うのが通常だと思われるけど、これは XFF があったら最後の IP を単に返すだけ。一方このプラグインではプライベートネットワークなアドレスは無視するようになっているので、

X-Forwarded-For: 192.0.2.100 10.0.0.2 10.0.0.1

みたいの受け取った時に、

$c->tx->remote_address;  # => '10.0.0.1'
$c->clien_ip;            # => '192.0.2.100'

こういう違いが出る。XFF がなかったり、全てプライベートアドレスだったりした場合は $c->tx->remote_address が呼ばれるので、環境やミドルウェア的なものにあんまり左右されずに『ユーザーの IP』っぽいものをとりたい時に普段使いできるはず。

通常これだけで事足りるはずだけど、事情があって無視したい グローバル IP があったりもしたので、任意の IP を追加で無視できるようにもなってる。これも SYNOPSIS の通り、

plugin 'ClientIP', ignore => [qw(192.0.2.1 192.0.2.16/28)];

CIDR 使えるので楽。

さすがに手段も目的も当たり前すぎるものなのでもうプラグインあるだろと思ったけどみあたらなかったので作った。

Aug 26, 2015

最後かもしれない YAPC::Asia Tokyo 行ってきた。

久しぶりに2日間参加できてとても有意義だった。 といっても 2006 年の初回から計 9 回行っても素人の域を脱することができないためずっとトークを聞いていた(その割にベストトーク上位3つをどれも聞いていないかった...)。

印象深かったのは以下。

Effective ES6

残念ながらいわゆる片手間でフロントエンドもやっている身としては大変ためになった。 今メインで開発しているサービスでも使い始めたのでいい加減覚える。

TBD

Ruby の反省点として Lisp に(悪)影響を受けた部分のくだりの、 「ユーザーに微妙な使い分けを強いるような似たようで異なるもの導入すべきではない」というの、Web サービスの API 設計に通じるものがありそう。 API 作ってるときはその API を安定させるためにやることを 1 つにさせたいと思って作ることが多い。ただ、実際にはそのせいでクライアントは微妙に異なる複数の API を条件分けして使ったりで全体を通すと API 提供側でよしなにやったほうがテストもし易いのではという気がする。 次、そんな場面に出くわしたらちょっと考えてみよう。

Perl 5.22 and You

5.20 で導入されてた Post Dereferencing は見落としていたので知れてよかった。

ただ、5.24 についてもさらりと触れていたけど、今後並行処理サポートとか(Ruby で検討されてるらしい)Soft Typing みたいな新しい技術は入ってこないんだろうなという気がするのでなかなか寂しい状況。 Perl 5 と Perl 6 は違う言語であるということはさんざん言われてるけど、そうであれば Perl 6 が登場しようとしてる今 Perl 5 が単に死にゆく old version になるのか、別の言語として発展し続けるのか、その辺ちょっとメッセージがほしいかなぁと思った(自分がしらないだけでなんかすでにあるかしら?)。

Adventures in Refactoring

Developer Happiness、いい言葉だった。もろもろ共感する部分あり、身につまされる部分あり、なるほど感あり、とてもいいトークだった。 そいえばテストコードのリファクタリングはどうやって進めてるのか、きいてみればよかったと今更思った。 あとでもう一回スライド見直して脳内再生しよう

Parallelism, Concurrency, and Asynchrony in Perl 6

トークの聞きやすさ、わかりやすさもあいまってか、Perl 6 の並列、平行、非同期部分えらく良さそうに見えた。 言語のコア機能じゃなくてモジュールで実現されてるみたいなっぽいのでなんか変態的な気もするけど、Perl 6 ちょと期待してもいいのかなと思った。


YAPC::Asia は初回の思い出が強すぎるせいか、あの時のような YAPC をもっかい見てみたいという気もする(他力本願)。 一方で Perl の話メインでみっちりトークをするという役目は地域.pm に移ったかなという気はずっとしてたので、自宅の最寄りでもある Chiba.pm がまた開催されるようなら行ってみよう。

またトークばかり聞いてるだけかもしれないけど、そんなに遠くない未来にまた開催されるといいなぁ。

Jan 14, 2015

Data::ObjectDriver 0.10 をリリースした。

SIXAPART/Data-ObjectDriver-0.10

テストとドキュメントの修正だけのバージョンだけど 0.09 から 4 年弱を経ての復活。

大人の事情で宙ぶらりんになっていた PAUSE の SIXAPART アカウントを復活しつつ、前メンテナの Yann から Github 上のリポジトリを transfer してもらい再び Six Apart としてメンテナンスすることに。

sixapart/data-objectdriver

Pull Request もながらく放置されてしまっているけどなるだけ近いうちに対応する方向で。Movable Type をはじめその他のサービスでも使っているので、今後はそれなりにメンテナンスされていくことになるはず。

ご利用中の皆様におかれましては引き続きよろしくお願い致します🙇

Aug 04, 2014

Vagrant で NFS 使っての開発環境で、ローカルでファイル変更してるんだけど VM 上の plack -R が変更検知してくれないなぁ、とおもってしばらく使ってたけど、やっぱり不便なので調べたらどうやらこれは NFS と Inofity の問題でどうしようもなさそうだった。

http://stackoverflow.com/questions/4231243/inotify-with-nfs

-R の実装である Plack::Loader::Restarter が使う Filesys::Notify::Simple では Linxu::Inofity2 なければ、File::Find 使ってフルスキャンしつつの変更検知ができるようにはなってる。それでええやん、というのもあるがバッテリー作業時の電池節約もしたいので別の方法を模索。

今回はもともと Grunt 使ってたのもありどうせならということで Grunt で完結するようにしてみた。

HTTP::Server::PSGI 使ってたこんなような Procfile のところを、

admin: plackup -p 9001 -R lib -a conf/admin.psgi

(どうせ本番で使う)Server::Starter + Starlet の構成にして pid をファイルに記録しつつの起動に変更。

admin: start_server --port=9001 --pid-file=var/run/admin.pid -- plackup -a conf/admin.psgi -s Starlet --max-workers=1

Grunt では watch で .pm ファイル達を監視しつつの exec するタスクを追加。

watch:
  apps:
    files: ['lib/**/*.pm']
    tasks: ['exec:reload']
exec:
  reload:
    command: 'vagrant ssh -c "kill -HUP `cat /vagrant/var/run/admin.pid`" -- -t'

これでローカルで Grunt 走らせておけば変更検知しての再起動がいい感じに。

ただし、grunt-contrib-watch は非常に負荷が高いようなので grunt-este-watch に移行したほうが良さそう(ファイル数にもよるだろうけど実際ロードが 20% ぐらい上がった)。

http://tech.nitoyon.com/ja/blog/2013/10/10/grunt-watch-slow/

とりあえずまともに動く plack -R の代替ができて普通の状態に戻った。

Jun 24, 2013

前の記事をつぶやいたら、@kazeburo さんから、

というのを教えてもらった!

前の記事でははしょったけど、redis、nginx なんかもうごいててまぁ再起動しても一瞬なんだけど、もったいない感があったので、

の通り、gearman worker は App::watcher で変更検知、plackup は -r とか -R で、というふうにしてみた。

#!/usr/bin/env perl
use strict;
use warnings;
use utf8;

use Proclet;
use FindBin ();
use Cwd ();

my $lib = Cwd::abs_path("$FindBin::Bin/../lib");

my $proclet = Proclet->new(color => 1);
$proclet->service(
    tag  => 'gearmand',
    code => 'gearmand -p 7003 --debug 1',
);

$proclet->service(
    tag  => 'gearman-worker',
    code => 'watcher --dir lib --signal HUP -- perl -Ilib script/gearman-worker --jobs Foo',
);

$proclet->service(
    tag  => 'api',
    code => 'plackup -Ilib -p 3000 -R $lib  -s Starlet --workers 2 etc/api.psgi',
);

$proclet->run;

すっきり。cpanfile には以下を入れておくと多分エコ。

on 'develop' => sub {
    requires 'App::watcher';
    if ($^O eq 'linux') {
        requires 'Linux::Inotify2';
    }
    elsif ($^O eq 'darwin') {
        requires 'Mac::FSEvents';
    }
};

同じディレクトリ以下を複数のプロセスで watch してるんだけど、そのへんエコじゃないかもしれないけど。

Proclet を使って開発環境用のもろもろを起動している時、Web アプリは morbo や plackup -R でファイルの変更を検知して自動再起動をやってくれるけど、たとえば自分で書いた Gearman や TheSchwartz の Worker とかのプロセスを再起動わすれたまま、うまくうごかん、とかいってうんうんうなっている時があったりなかったり。一回 CTRL-C で抜けて再起動する、というのももったいないし、そういうのもファイル変更検知して再起動ができるようになるといいなぁ、と思ってやってみた。

元々の Proclet による起動スクリプト(scripts/start.pl)

#!/usr/bin/env perl
use strict;
use warnings;
use utf8;

use Proclet;

my $proclet = Proclet->new(color => 1);
$proclet->service(
    tag  => 'gearmand',
    code => "gearmand -p 7003 --debug 1",
);   
$proclet->service(
    tag => 'gearman-worker',
    code => "perl -Ilib script/gearman-worker --jobs Foo",
);
$proclet->service(
    tag  => 'api',
    code => "plackup -Ilib -p 3000 -R lib -s Starlet --workers 2 etc/api.psgi",
);
$proclet->run;

ファイル変更検知したら指定のコマンドを実行する簡単なスクリプト(script/ukiuki)を用意。

#!/usr/bin/env perl
use strict;
use warnings;
use utf8;

use Getopt::Long qw( :config posix_default no_ignore_case gnu_compat auto_help );
use Pod::Usage;
use Filesys::Notify::Simple;

GetOptions(\my %opt, qw( watch=s call=s h|help )) or pod2usage(1);
my @dirs = split /,/, $opt{watch};

my $watcher = Filesys::Notify::Simple->new(\@dirs);
$watcher->wait(sub { exec $opt{call} });

Proclet からは start_server 経由で起動するようにして pid とりつつ変更検知してその pid (start_server) のプロセスに HUP を投げる感じに変更。

#!/usr/bin/env perl
use strict;
use warnings;
use utf8;

use Proclet;

my $proclet = Proclet->new(color => 1);
$proclet->service(
    tag  => 'gearmand',
    code => "gearmand -p 7003 --debug 1",
);

my $gearman_pid = "var/gearman-worker.pid";
$proclet->service(
    tag  => 'gearman-worker',
    code => "start_server --pid-file=$gearman_pid -- perl -Ilib script/gearman-worker --jobs Foo",
);

my $api_pid = "var/web.pid";
$proclet->service(
    tag  => 'api',
    code => "start_server --pid-file=$api_pid --port 3000 -- plackup -Ilib -s Starlet --workers 2 etc/api.psgi",
);

$proclet->service(
    tag  => 'watch',
    code => "perl -Ilib script/ukiuki --watch lib --call 'kill -HUP `cat $gearman_pid $api_pid`'",
);

$proclet->run;

起動する。

$ carton exec script/start.pl
16:54:03 api.1            | start_server (pid:33682) starting now...
16:54:03 api.1            | starting new worker 33686
16:54:03 gearman-worker.1 | start_server (pid:33681) starting now...
16:54:03 gearman-worker.1 | starting new worker 33687
16:54:03 gearman-worker.1 | [33687] [info] Starting gearman worker for 'Foo' jobs
16:54:04 api.1            | Plack::Handler::Starlet: Accepting connections at http://0:3000/

lib 以下のファイルをなにがしか変更して保存して戻ってくる。

16:55:01 gearman-worker.1 | received HUP, spawning a new worker
16:55:01 api.1            | received HUP, spawning a new worker
16:55:01 gearman-worker.1 | starting new worker 33799
16:55:01 api.1            | starting new worker 33798
16:55:01 gearman-worker.1 | [33799] [info] Starting gearman worker for 'Foo' jobs
16:55:02 api.1            | Plack::Handler::Starlet: Accepting connections at http://0:3000/
16:55:02 gearman-worker.1 | new worker is now running, sending TERM to old workers:33687
16:55:02 api.1            | new worker is now running, sending TERM to old workers:33686
16:55:02 gearman-worker.1 | old worker 33687 died, status:0
16:55:02 api.1            | old worker 33686 died, status:0

再起動された〜。

なんかたまに2回立て続けに HUP なげられてしまうとか起きてるけど(なぜだ)とりあえず使そうではある。とはいえもうちょっとスマートにならんかな。

追記: App::watcher でスマートになった

Jun 10, 2013

あるアプリで、まぁまぁ大きいYAML形式の設定ファイルを復数つかっていて、特別な理由がないまま(昔はあったのかもしれない) YAML.pm、YAML::Syck 両方を使っていたのを、なんとなく YAML.pm で統一しようかなぁと思い、念のためベンチとってみた。YAML::XS も添えて。

#!/usr/bin/env perl
use strict;
use warnings;

use Benchmark qw( cmpthese );
use YAML ();
use YAML::Syck ();
use YAML::XS ();

open my $fh, '<', shift;
my $data = do { local $/; <$fh> };
close $fh;

cmpthese(100, {
    'YAML(' . $YAML::VERSION . ')'  => sub {
        YAML::Load($data);
    },
    'YAML::XS(' . $YAML::XS::VERSION . ')' => sub {
        YAML::XS::Load($data);
    },
    'YAML::Syck(' . $YAML::Syck::VERSION . ')' => sub {
        YAML::Syck::Load($data);
    },
});

6200行くらいあるもののそんなに複雑じゃない(アンカー&エイリアスや複数行データとかない) YAML ファイルのパースの結果、

➜ perl yaml-parser-bench.pl foo.yaml
                    Rate       YAML(0.84) YAML::Syck(1.27)   YAML::XS(0.41)
YAML(0.84)       0.969/s               --             -98%             -99%
YAML::Syck(1.27)  59.2/s            6007%               --             -21%
YAML::XS(0.41)    74.6/s            7602%              26%               --

と、おもいのほか差がでた。アプリの起動時にはこれ以外にも何個かYAMLの読み込みがあって、YAML.pm に変更したところ明らかに起動もおそく...。

なので、YAML.pm ではなく YAML::Syck の方に寄せるか YAML::XS に行ってみるかだけど、なんとなく YAML::XS だろうか。libsyck (YAML::Syck) v.s. libyaml (YAML::XS) の図でいうと libyaml のほうが広く使われている気配を感じなくもないが、よくはわからない...。

May 31, 2013

CPAN にあがっている MogileFS::Plugin::FilePaths には、rename コマンドで index 使わないような query なげてしまう問題があるので以下パッチをあてること。

diff --git a/lib/MogileFS/Plugin/FilePaths.pm b/lib/MogileFS/Plugin/FilePaths.pm
index 6924dc6..1056911 100644
--- a/lib/MogileFS/Plugin/FilePaths.pm
+++ b/lib/MogileFS/Plugin/FilePaths.pm
@@ -264,8 +264,8 @@ sub load {
         my $dbh = Mgd::get_dbh();
         return undef unless $dbh;

-        $dbh->do('UPDATE plugin_filepaths_paths SET parentnodeid=?, nodename=? WHERE parentnodeid=? AND nodename=?', undef,
-                 $new_parentid, $new_name, $old_parentid, $old_name);
+        $dbh->do('UPDATE plugin_filepaths_paths SET parentnodeid=?, nodename=? WHERE dmid=? AND parentnodeid=? AND nodename=?', undef,
+                 $new_parentid, $new_name, $dmid, $old_parentid, $old_name);

         # UNLOCK rename

このパッチ自体は Github 上の master にはだいぶ前にとりこまれているけど、0.03 はいまだリリースはされていない。

という備忘録。

Apr 19, 2013

この前、さくらの VPS が落ちて再起動されてしまったのち、いっしょに死んだままだった MT を久々に起動するにあたり carton 化しようとおもって作った cpanfile。

Starlet は適宜使いたいサーバーに、Server::Starter、XML::LibXML は不要であれば外しつつ、MySQL じゃないひとは DBD::mysql も適当に変更して、carton install すればできあがり。

% carton exec -- local/bin/start_server --port 8000 --pid-file=log/mt.pid -- plackup -s Starlet --max-workers=2 --access-log=log/access.log mt.psgi >& logs/error.log &

みたいな感じで起動。しかし、ログローテートもしてないしあんばいがよくないので supervisor で動かすようにする。いつか...。

Apr 05, 2013

CPAN Module の変更点をサクッと調べる方法

というエントリーに反応してみるテスト。

僕は CPAN Module のバージョン間の diff をとるのに、search.cpan.org にある diff 機能を使う以下のようなやっつけスクリプトを使ってる。

たまに空のレスポンスが返ってきたりするけど....、これを less とか grep -A100 .pm とかなんとかにパイプしたりしなかったりしてコマンドラインで生 diff を確認。Cache::Memcached::Fast の 0.19 と 0.20 だったら以下の様な塩梅。

パッケージまるごとの diff なので README とか、MANIFEST とかの差分もはいっててノイズがまぁまぁあるといえばあるけど、目 grep で除外...。

metacpan っていまだによくわかってないけど(汗)、同じようなのあるかしら。