しょんぼり技術メモ

まいにちがしょんぼり

MessagePack RPC for Rubyのタイムアウト系のエラーについてのメモ

忘れてたので自分用にまとめておく。

サーバ側:

require 'msgpack/rpc'

class MyServer
  def ping_sync
    "pong"
  end

  def ping_async
    as = MessagePack::RPC::AsyncResult.new
    # as.result("pong")
    as.result("pong at #{Time.now}")
    return as
  end

end

mysvr    = MyServer.new
mpserver = MessagePack::RPC::Server.new
mpserver.listen("127.0.0.1", 18888, mysvr)
mpserver.run

同期呼び出しのときのテスト。

require 'msgpack/rpc'

ret      = nil
mpclient = nil

begin
  mpclient = MessagePack::RPC::Client.new("127.0.0.1", 18888)
  mpclient.timeout = 1
rescue
  # この時点でサーバがListenしていなかった場合、
  # ここでTimeoutするように見える…が、実はそうでもない。ここではなにもraiseされてこない。
  puts "caught: #{$!.inspect}"
  exit 1
end

puts "--- call sync"
begin
  puts "calling mpclient.call(:ping_sync)"
  ret = mpclient.call(:ping_sync)
  puts "ret: #{ret}"
rescue
  # callしたときにサーバがListenしていないと、MessagePack::RPC::ConnectionTimeOut例外が上がる
  puts "caught: #{$!.inspect}"
  # -> caught: #<MessagePack::RPC::ConnectionTimeoutError: connection timed out>
  exit 1
end

非同期呼び出しのときのテスト。

require 'msgpack/rpc'

ret      = nil
mpclient = nil

begin
  mpclient = MessagePack::RPC::Client.new("127.0.0.1", 18888)
  mpclient.timeout = 10
rescue
  # この時点でサーバがListenしていなかった場合、
  # ここでTimeoutするように見える…が、実はそうでもない。ここではなにもraiseされてこない。
  puts "caught: #{$!.inspect}"
  exit 1
end

future = nil
begin
  puts "calling mpclient.call_async(:ping_async) at #{Time.now}"
  future = mpclient.call_async(:ping_async) # 返値はFutureクラス、この時点ではサーバ側では処理が行われない
  puts "future.class = #{future.class}"
rescue
  # call_asyncした時点でサーバがListenしていない場合でも、ここではなにもraiseされてこない。
  puts "caught: #{$!.inspect}"
end

puts "sleeping for 5 sec."
sleep 5

begin
  puts "-> calling Future.get"
  ret = future.get
  puts "ret = #{ret} / Time.now=#{Time.now}"
  puts "future.class = #{future.class}"
  puts "ret.class    = #{ret.class}"
rescue
  # ここで初めてping_asyncの処理が走る。サーバがListenしていない場合には例外が上がる
  puts "caught: #{$!.inspect}"
  # 最初からサーバがListenしていなかった場合:
  # -> caught: #<MessagePack::RPC::ConnectionTimeoutError: connection timed out>
  # 最初はサーバがListenしていたが、処理中に時間がかかりすぎてタイムアウトした場合:
  # -> caught: #<MessagePack::RPC::TimeoutError: request timed out>
  exit 1
end

asyncの実行結果:

calling mpclient.call_async(:ping_async) at 2011-11-08 16:49:00 +0900 # call_asyncを呼んだのは16:49:00
future.class = MessagePack::RPC::Future
sleeping for 5 sec.
-> calling Future.get
ret = pong at 2011-11-08 16:49:05 +0900 / Time.now=2011-11-08 16:49:05 +0900 # サーバ側でping_asyncが呼ばれたのは16:49:05
future.class = MessagePack::RPC::Future
ret.class    = String

要約:

  • Client.newした時点でサーバがListenしていなくても例外は上がらない
  • call, call_asyncした時点でサーバがListenしていないとMessagePack::RPC::ConnectionTimeoutErrorが上がる
  • call, call_asyncしてサーバが処理をしているとき、時間がかかりすぎてタイムアウトした場合にはMessagePack::RPC::TimeoutErrorが上がる
  • call_async(:remote_func, args) で呼び出したとしても、サーバ側ではまだremote_funcは呼び出されない。返値のfutureに対してgetを呼ぶと初めて実行が行われる