ziguzagu.org

Proclet で起動しているアプリをファイル変更検知して再起動

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