Gearman で Capistrano の shell 機能みたいなのを

Gearman で遊んでたら思いついたので書いておきます。ネタに近い。
複数台のマシンで同じコマンドを実行して結果を見たい、てなのを Gearman でやってみる。

  • worker: 自分の hostname を function 名として job server に登録。job の引数に受け取った文字列を shell に食わせて実行する
  • client: worker の動いているマシンの hostname を function 名として、実行したい shell command を投げる

てなかんじ。
あらかじめ job_server になるマシンは決めて gearmand を実行しておき、コマンドを実行したいマシンで worker.pl を起動。

$ perl worker.pl sola # 引数は job_server名
job_server: sola
myhostname: sola
$ perl gworker.pl sola
job_server: sola
myhostname: white.internal

client.pl を実行してコマンド送信すると、

$ perl client.pl sola white.internal sola  # 最初の引数がjob_server、以降がworkerのmyhostnameで表示されるホスト名
job_server: sola
hostnames : white.internal sola
> uptime
==== sola ====
 03:20:58 up 211 days, 22:52,  1 user,  load average: 0.00, 0.10, 0.10

==== white.internal ====
 3:20  up 62 days, 27 mins, 4 users, load averages: 0.09 0.12 0.11

> uname -a
==== sola ====
Linux sola 2.6.19-gentoo-r5 #1 SMP PREEMPT Thu Feb 15 17:40:12 JST 2007 i686 Intel(R) Pentium(R) M processor 1.60GHz GenuineIntel GNU/Linux

==== white.internal ====
Darwin white.internal 8.10.1 Darwin Kernel Version 8.10.1: Wed May 23 16:33:00 PDT 2007; root:xnu-792.22.5~1/RELEASE_I386 i386 i386

こうなる。
手間がかかる割には面白くなかったような……

#!/usr/bin/perl
# worker.pl
use strict;
use Gearman::Worker;
use Sys::Hostname;
use Perl6::Say;

my $job_server = shift || die "no job server\n";
my $hostname   = hostname();
say "job_server: $job_server";
say "myhostname: $hostname";
my $worker   = Gearman::Worker->new;
$worker->job_servers($job_server);
$worker->register_function(
    $hostname => sub {
        my $job = shift;
        my $command = $job->arg;
        return qx{ $command };
    },
);
$worker->work while 1;
#!/usr/bin/perl
# client.pl
use strict;
use Gearman::Client;
use Perl6::Say;
my $timeout  = 30;
my ( $job_server, @hostname ) = @ARGV;
die "no job server\n" unless $job_server;
say "job_server: $job_server";
say "hostnames : @hostname";

my $client = Gearman::Client->new;
$client->job_servers($job_server);

while (1) {
    print "> ";
    my $cmd = <STDIN>;
    chomp $cmd;
    my $taskset = $client->new_task_set;
    for my $h (@hostname) {
        $taskset->add_task(
            $h => \$cmd,
            {
                on_complete => sub {
                    say "==== $h ====";
                    say ${ $_[0] };
                },
            }
        );
    }
    $taskset->wait( timeout => $timeout );
}