Data::ObjectDriver 0.10

  • 投稿日:
  • by
  • カテゴリ:  

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 をはじめその他のサービスでも使っているので、今後はそれなりにメンテナンスされていくことになるはず。

ご利用中の皆様におかれましては引き続きよろしくお願い致します[E:#x1F647]

Vagrant な開発環境の puppet manifest を使いまわす

  • 投稿日:
  • by
  • カテゴリ:    

vagrant + puppet を使っての開発環境を作る場合に、いままでは、

  • プロジェクト直下に vagrant.pp をおいてそこにすべてを詰め込む
  • file resource を定義するとき、source で指定するファイルはプロジェクトで使う他の設定ファイル用のディレクトリに混ぜ込んでおいておいてフルパスハードコードで参照
source => '/vagrant/conf/my.cnf'

としていた。これはこれで機能していたし、手作業で構築する部分はゼロだった。ただ、この manifest を使いまわして puppet apply してAWS 上やら社内サーバーやらに QA 用の環境用意しようとなったとたん使い回しが効かなくて manifest 都度手直しとかするはめになってしまうことに気づいた。(まぁ、その環境でも /vagrant に git clone してもらえればそれはそれでいいんだけど...)

結局 manifest にフルパスをハードコードしないためには、モジュール化して、

source => 'puppet:///modules/mysql/my.cnf'

などとして参照できるようにすれば puppet apply --modulepath でどこに clone しても動く manifest になる。ということで、いまは以下の様な感じで作るのが自分の中のベストプラクティスとなった。

puppet
├── mysql
│   ├── files
│   │   └── my.cnf
│   └── manifests
│       └── init.pp
├── pound
│   ├── files
│   │   ├── example.com.pound.crt
│   │   └── pound.cfg
│   └── manifests
│       └── init.pp
└── site.pp

という感じで file resource 必要な奴はモジュール化。Vagrantfile は、

config.vm.provision :puppet do |puppet|
   puppet.module_path    = "puppet"
   puppet.manifests_path = "puppet"
   puppet.manifest_file  = "site.pp"
   puppet.options        = "--verbose"
end

とする。

これで、vagrant 使ってれば vagrant provision でもちろん行けるし、そうでない環境をどうにかしたいときには git clone してきて、

puppet apply --modulepath=$PWD/puppet puppet/site.pp

とすればよいだけ。

一手間あるといえばあるけど、アプリケーションが直接使うわけでもない my.cnf みたいなものを自然と別ディレクトリに分離できるし、心理的にもスッキリした感。しばらくこれでよさげ。

Vagrant + NFS な開発環境でのアプリ自動再起動

  • 投稿日:
  • by
  • カテゴリ:    

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 の代替ができて普通の状態に戻った。

zaw で tmux の pane 内の文字列から補完

  • 投稿日:
  • by
  • カテゴリ:  

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 により部分一致できるようになったのでだいぶ具合がよくなった。

前の記事をつぶやいたら、@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 で起動しているアプリをファイル変更検知して再起動

  • 投稿日:
  • by
  • カテゴリ:  

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 でスマートになった

Benchmark of Perl's YAML Parser

  • 投稿日:
  • by
  • カテゴリ:  

あるアプリで、まぁまぁ大きい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 のほうが広く使われている気配を感じなくもないが、よくはわからない...。

Apache 1.3/2.2 を foreground で動かす

  • 投稿日:
  • by

mod_perl1 べったりな古いアプリを PSGI 化したいんだけどその前に Proclet 化したい。のでどちらも foreground でうごかしたい。

フロントエンドにいる 2.2 はこちらのとおり、

httpd2 -D NO_DETACH -D FOREGROUND ...

ですんなり。1系は NO_DETACH, FOREGROUND ではうまく行かなかったので、なんとかできないかぁ、と思って -h でみたらなんてことない -F オプションつけるだけだった。

httpd -F ...

あとは起動前にいろいろモニョモニョしてるところをなんとかできれば Proclet 化はいけそう。やっほい。

MogileFS::Plugin::FilePaths 0.02 にはパッチをあてること

  • 投稿日:
  • by
  • カテゴリ:  

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 はいまだリリースはされていない。

という備忘録。