本の続きに戻ります。サーバを停止させた状態でリモート呼び出しをしたらどうなるか実験してみます。puts00のサーバーを停止してthere.putsを実行っと。
DRb::DRbConnErrorという例外が発生しました。 DRbConnErrorはdRuby内部で通信エラーが発生したことを示します。サーバが停止してしまったので、メソッド呼出しに失敗してしまったのです。2.1.2. irbからの利用
確かに本の通りにDRbConnErrorがでました。
def initialize(remote_uri) # :nodoc: @uri = remote_uri @protocol = DRbProtocol.open(remote_uri, DRb.config) end
場所はここ、DRbConnのインスタンス生成時のDRbProtocol.open。このメソッドは
def open(uri, config, first=true)
@protocol.each do |prot|
begin
return prot.open(uri, config)
rescue DRbBadScheme
rescue DRbConnError
raise($!)
rescue
raise(DRbConnError, "#{uri} - #{$!.inspect}")
end
end
・・・
です。このprot.openでは、実際にはDRbTCPSocketのクラスメソッドopenが呼ばれるので、この中のTCPSocket.openで例外が発生している感じですね。それをrescueでつかまえてraiseしてるのか。ふむふむ。ではopenは成功したけどその後に通信エラーになった場合はどうなるのかなあ。DbConnのopenの中身の一部です。
・・・
@pool.each do |c|
if conn.nil? and c.uri == remote_uri
conn = c if c.alive?
else
new_pool.push c
end
end
@pool = new_pool
・・・
プールから取る時の、「conn = c if c.alive?」で、この時点でサーバー側が死んでいたらそれを使わないようになっています。で、もしここでも接続は生きてたけど、送信までに死んだ場合は、recv_replyのどこかで例外が出るようです。
ここでは、@poolの要素群をnew_poolという入れ物に一度移し替えて、それを@poolに戻しています。ただ今回使われることになった接続オブジェクトは、この時点ではnew_poolに入っていません。プールに接続オブジェクトを入れているのは、その下に記載されているのensureです。(ensureってのは、javaでいうfinallyみたいなやつです。)
@pool.unshift(conn) @pool.pop.close while @pool.size > POOL_SIZE
新しいconnをプール用配列の先頭に入れ、プールの要素数の上限を越えた要素は取り除いて閉じる。ってことか。whileも右側に書けるのですね。かっこいいコードだなあ。
ところで、サーバーは無事生きているけど、リモートオブジェクトに存在しない操作を行なった場合はどうなるのでしょうか。ここではhogeメソッド(Putsに存在しない操作)を呼んでみました。
there.hoge
すると以下のようなresultになりました。ちなみに、成功/失敗が設定されるsuccの値はfalseになっています。
result undefined method `hoge' for #<Puts:0x29ba790 @stream=#<IO:0x294e758>>