ソケット経由で非同期にコマンドを実行する

 POE習作につき。
 まず実行スクリプト

#!/usr/bin/env perl

use strict;
use warnings;

use IO::Socket::INET;

my $sock = IO::Socket::INET->new("localhost:12345");
$sock->timeout(10);
$sock->say("wait:5");
$sock->say("wait:2");

$sock->shutdown(2);

exit(0);

 ソケットサーバ

#!/usr/bin/env perl

use strict;
use warnings;

use POE qw/Component::Server::TCP Wheel::Run/;
use POE::Sugar::Args;

#via http://d.hatena.ne.jp/sfujiwara/20070209/1171010387
#sub Socket::SOMAXCONN { 1024 }

POE::Session->create(
    inline_states => {
        _start => sub {
            my $poe = sweet_args;
            $poe->kernel->sig( CHLD => "got_sigchld" );
            my $server = POE::Component::Server::TCP->new(
                Port                  => 12345,
                ClientConnected       => \&client_connect_handler,
                ClientDisconnected    => \&client_disconnect_handler,
                ClientInput           => \&client_input_handler,
                ClientShutdownOnError => 1,
            );
            $poe->heap->{server} = $server;
        },
        got_child_stdout => \&child_stdout_handler,
        got_sigchld      => \&sigchld_handler,
    }
);

POE::Kernel->run;
exit(0);

sub client_input_handler {
    my $poe            = sweet_args;
    my ($client_input) = @{ $poe->args };
    POE::Wheel::Run->new(
        Program     => './sleep.pl',
        ProgramArgs => [$client_input],
        StdoutEvent => 'got_child_stdout',
    );
    print "[POE] input: $client_input\n";
}

sub client_connect_handler {
    my $poe = sweet_args;
    my $ip  = $poe->heap->{remote_ip};
    print "[POE] connected from $ip\n";
}

sub client_disconnect_handler {
    my $poe = sweet_args;
    my $ip  = $poe->heap->{remote_ip};
    print "[POE] $ip disconnected\n";
}

sub child_stdout_handler {
    my $poe = sweet_args;
    my ($record) = @{ $poe->args };
    print "[POE][STREAM] $record\n";
}

sub sigchld_handler {
    my $child_pid = sweet_args->args->[1];
    print "[POE] sigchld: $child_pid\n";
    return 0;
}

 ソケットサーバから叩かれるsleep.pl

#!/usr/bin/env perl

use strict;
use warnings;

use IO::File;

my $client_input = shift;

if($client_input =~ /^wait:(\d+)/) {
  my $wait = $1;
  sleep $wait;
}

#出力についての理解が浅いため…
my $f = IO::File->new('test.txt', 'a');
$f->say($client_input);
$f->close;
print "[input] $client_input\n";

exit(0);

 出力は、まずサーバ側

[POE] connected from 127.0.0.1
[POE] input: wait:5
[POE] input: wait:2
[POE] 127.0.0.1 disconnected
[POE] sigchld: 12959
[POE] sigchld: 12958

 「wait:5」の方が先に入力されてる。sleep.plでのファイルへの出力は

wait:2
wait:5

 期待通り、「wait:2」の方が先に処理が終わってる。
 ただ、よくありがちっぽい問題なので、既に誰かがもっといい解決法を見つけてるのかも…。
 個人的には、POE::Wheel::Runではなく(つまりコマンドで呼び出すのではなく)、ソケットサーバ内に処理を書くなりUSEできて、実行関数をP::W::Run->newのところで叩けれるようになれば、実行時間がロード時間分短縮されて、メモリにも優しいかな、と思ってる。とりあえず、それは(今の僕だと)一筋縄にいかないことだけは分かった。