May 30, 2014

zaw がよいそうなので使い始めてみた。

基本的なところ設定したあと、とりあえずこれがないと始まらないということで、tmux の現在の pane 内に表示されてる文字列を補完対象にするやつだけ追加で書いた。

function zaw-src-tmux-pane-strings() {
    candidates=($(tmux capture-pane\; show-buffer \; delete-buffer | sed '/^$/d' | sed '$ d'))
    actions=("zaw-callback-append-to-buffer")
    act_descriptions=("append to edit buffer")
    return 0
}
zaw-register-src -n tmux-pane-strings zaw-src-tmux-pane-strings
bindkey '^x^o' zaw-tmux-pane-strings

zsh + tmux で同じことやってはいてこれはこれで便利だったけど、先頭一致しないと絞りこまれないのが不便だった(zsh レベルが低いだけでうまいことやる方法知らないだけか?)。それがzaw により部分一致できるようになったのでだいぶ具合がよくなった。

Feb 09, 2014
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 でファイルの変更を検知して自動再起動をやってくれるけど、たとえば自分で書いた Garman や 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 のほうが広く使われている気配を感じなくもないが、よくはわからない...。