AnyEvent::JSONRPC::Liteを使う。
JSONRPCサーバを立ててクライアントからのリクエストを非同期で返したいという課題
サーバのスクリプトは以下の通り。
use strict; use warnings; use AnyEvent::JSONRPC::Lite; use Data::Dumper; my $cv = AE::cv; my $server = AnyEvent::JSONRPC::Lite::Server->new( port => "12345" ); $server->reg_cb( echo => sub { my ( $res_cv, @params ) = @_; if ( $params[0] eq "call_2" ) { for my $dummy ( 1 .. 100000000 ) { } } $res_cv->result(@params); }, ); $cv->recv;
クライアントは下記の通り。
use strict; use warnings; use AnyEvent::JSONRPC::Lite; use Data::Dumper; my $query = $ARGV[0]; my $client = AnyEvent::JSONRPC::Lite::Client->new( host => "127.0.0.1", port => "12345" ); my $cv = AE::cv; my $d = $client->call( "echo", $query ); $cv->begin; $d->cb( sub { print $d->recv; $cv->end; } ); $cv->recv;
server.plを実行してサーバを立ち上げる。
「client.pl call_1」とか「client.pl call_2」という風にリクエストを投げる。サーバサイドの処理でcall_2というクエリがあった場合は処理に時間がかかるようにわざと設定している。
「client.pl call_2」を実行してすぐに「client.pl call_1」を実行した時に最初の処理で詰まらずにcall_1の結果が返ってきて欲しいのだが、上記ではダメ。
解決策はこれから考える。io監視をすればいいのかな?
続きを書きました。
上記の解決策はクライアント側にio監視のイベントループを設定すれば、call_2のレスポンスが遅くてもcall_1が先に返ってきた時はそちらを先に処理してくれるだろうと考えました。
ですが、結果からいうとダメでした。そもそもサーバの処理でブロックしているということなのでしょうか。
下記にクライアントのコードを記述します。
正しい解決策はダウンロードたけしさんが教えてくださいました。のでリンクを参照してねw。あーんとす!
use strict; use warnings; use AnyEvent::Handle; use AnyEvent::Socket; use Data::Dumper; my $query = $ARGV[0]; my $cv = AE::cv; tcp_connect "127.0.0.1", 12345, sub { my ($fh) = @_ or die "ERROR"; my $handle = AnyEvent::Handle->new( on_error => sub { die "on_error"; }, on_eof => sub { die "on_eof"; }, fh => $fh, ); $handle->push_write( json => { id => 1, method => "echo", params => [$query] } ); my $io_cv = AE::cv; my $w; $w = AnyEvent->io( fh => $fh, poll => "r", cb => sub { undef $w; $handle->push_read( json => sub { my ( $handle, $res ) = @_; $io_cv->send( $res->{result} ); } ); } ); $io_cv->cb( sub { $cv->send( $io_cv->recv ); } ); }; print $cv->recv;
そもそもを理解できていないのがバレました、というお話でした。