DRbでプロセスをまたがった大域脱出ができるか確認した
結論としてはできなかった。
Rubyのバージョン:
$ ruby -v ruby 2.6.2p47 (2019-03-13 revision 67232) [x86_64-linux]
確認用のコード:
require 'drb/drb' require 'drb/unix' require 'logger' stdlog = Logger.new(STDOUT) module Jump def ping yield('pong') end module_function :ping def occur(tag, value) throw(tag, value) end module_function :occur end druby_local_uri = 'drbunix:' + File.expand_path(File.join(File.dirname($0), "druby_local.#{$$}")) druby_remote_uri = 'drbunix:' + File.expand_path(File.join(File.dirname($0), "druby_remote.#{$$}")) stdlog.info("start local dRuby service: #{druby_local_uri}") DRb.start_service(druby_local_uri) pid = fork{ stdlog.info("start remote dRuby service: #{druby_remote_uri}") DRb.start_service(druby_remote_uri, Jump) DRb.thread.join } at_exit{ Process.kill('TERM', pid) } drb_remote_obj = DRbObject.new_with_uri(druby_remote_uri) stdlog.info('wait to start dRuby services') begin t0 = Time.now begin drb_remote_obj.ping{|r| r == 'pong' or raise 'failed ping.' } rescue DRb::DRbConnError if (Time.now - t0 >= 10) then raise end sleep(0.1) retry end rescue stdlog.fatal('failed to start dRuby services') stdlog.fatal($!) abort end stdlog.info('local jump test') begin r = catch(:foo) { Jump.occur(:foo, 'local_jump_test') nil } r == 'local_jump_test' or raise 'failed local jump test.' rescue stdlog.error('NG') stdlog.error($!) else stdlog.info('OK') end stdlog.info('remote jump test') begin r = catch(:bar) { drb_remote_obj.occur(:bar, 'remote_jump_test') nil } r == 'remote_jump_test' or raise 'failed remote jump test.' rescue stdlog.error('NG') stdlog.error($!) else stdlog.info('OK') end
確認結果:
$ ./druby_ipc_jump.rb I, [2019-04-12T00:25:00.940801 #4402] INFO -- : start local dRuby service: drbunix:/home/toki/git_work/ruby_examples/druby_local.4402 I, [2019-04-12T00:25:00.962852 #4402] INFO -- : wait to start dRuby services I, [2019-04-12T00:25:00.964105 #4404] INFO -- : start remote dRuby service: drbunix:/home/toki/git_work/ruby_examples/druby_remote.4402 I, [2019-04-12T00:25:01.072707 #4402] INFO -- : local jump test I, [2019-04-12T00:25:01.083738 #4402] INFO -- : OK I, [2019-04-12T00:25:01.083973 #4402] INFO -- : remote jump test E, [2019-04-12T00:25:01.100414 #4402] ERROR -- : NG E, [2019-04-12T00:25:01.100528 #4402] ERROR -- : uncaught throw :bar (UncaughtThrowError) (drbunix:/home/toki/git_work/ruby_examples/druby_remote.4402) ./druby_ipc_jump.rb:17:in `throw' (drbunix:/home/toki/git_work/ruby_examples/druby_remote.4402) ./druby_ipc_jump.rb:17:in `occur' (drbunix:/home/toki/git_work/ruby_examples/druby_remote.4402) /usr/local/lib/ruby/2.6.0/drb/drb.rb:1635:in `perform_without_block' (drbunix:/home/toki/git_work/ruby_examples/druby_remote.4402) /usr/local/lib/ruby/2.6.0/drb/drb.rb:1595:in `perform' (drbunix:/home/toki/git_work/ruby_examples/druby_remote.4402) /usr/local/lib/ruby/2.6.0/drb/drb.rb:1679:in `block (2 levels) in main_loop' (drbunix:/home/toki/git_work/ruby_examples/druby_remote.4402) /usr/local/lib/ruby/2.6.0/drb/drb.rb:1675:in `loop' (drbunix:/home/toki/git_work/ruby_examples/druby_remote.4402) /usr/local/lib/ruby/2.6.0/drb/drb.rb:1675:in `block in main_loop' ./druby_ipc_jump.rb:77:in `block in <main>' ./druby_ipc_jump.rb:76:in `catch' ./druby_ipc_jump.rb:76:in `<main>'
RubyのUncaughtThrowError
は大域脱出のtag
とvalue
の値を持つのでハンドリングできそうなものだが実装されてないのかな。