dRubyを使った、分散オブジェクトによる別プロセスの呼び出し

2014.10.02

はじめに

実案件にて開発を行っていると、ある特定の処理を別プロセスとして実行したいことがあるかと思います。

私の直近の案件では、ある外部コマンド(jar)をRubyからは呼び出せたが、Railsからは呼び出せなかったケースがありました。 この場合、外部コマンドをRubyの呼び出しは別プロセスとして起動しておき、Railsから呼び出すようにしたいです。(jarは直せなかった・・・)

実現するには様々な方法があるかと思いますが、今回はRubyのライブラリとして用意されているdRubyを使った方法について書きたいと思います。

dRubyについて

dRubyとは、Rubyが実行可能な環境であれば動かすことができる分散オブジェクトシステムです。追加してインストールする物がないため、別プロセスの起動・呼び出しを手軽に実行できることが特徴かと思います。

以下に、リファレンスマニュアルからの説明を引用します。

dRuby はRuby 専用の分散オブジェクトシステムです。 Ruby のみで記述され、TCP socket のような Ruby 本体が提供する 通信手段があれば追加のインストール物なしに利用可能です。

drbライブラリより

サンプルソース

では、dRubyを使ったプロセスの起動・呼び出し処理です。ソースは以下の2つに分かれます。

  • front.rb
    独立したRubyのプロセスとして起動する処理。今回はここに外部コマンド(jar)の呼び出しを実装する。

  • sample_controller.rb
    RailsのControllrで、ここから別プロセス上の(front.rbの)メソッドを呼び出す。


以下、それぞれのソースです。

1.front.rb

require 'drb/drb'
require 'open3'

class ProcServer
  def call_jar
    cmd = 'java -jar 問題のJAR.jar'
    out, err, status = Open3.capture3(cmd)
    err == '' ? true : err
  end
end

DRb.start_service("druby://127.0.0.1:1234", ProcServer.new)

DRb.thread.join

dRubyを使用するため、「require 'drb/drb'」をしています。
「class ProcServer〜」には、別プロセスとして動かしたい処理を実装します。今回はjarを外部コマンドとして起動し、その結果を返しています。
DRb.start_serviceにURIとProcServerのインスタンスを渡すことで、他のプロセスから呼び出せるようにします。
最後の「DRb.thread.join」で、DRbのスレッドが終了するのを待機します。

この処理は呼び出し元とは独立したRubyのプロセスとして動かすため、以下のコマンドで事前に起動させておきます。

$ ruby front.rb

2.sample_controller.rb

require 'drb/drb'

class SampleController < ApplicationController def index remote = DRbObject.new_with_uri "druby://127.0.0.1:1234" result = remote.call_jar puts result end end [/ruby]

こちらは別プロセスを呼び出す側です。「DRbObject.new_with_uri〜」で、先に起動したプロセスをリモートオブジェクトとして取得しています。
リモートオブジェクトを取得したら、後は普通のインスタンスメソッドの呼び出しのように「remote.call_jar」を行うことで、別プロセスのメソッドを呼び出しています。
戻り値も、普通のインスタンスメソッドと同様に受け取ることができます。

尚、今回は書いてませんが、別プロセス上のメソッド(今回でいうProcServer.call_jar)に引数を用意し、呼び出す側から渡すことも可能です。

まとめ

dRubyを使うと、別プロセスの起動・呼び出しが、普通のインスタンスメソッドと同じようにできることが分かりました。何かの役に立てば幸いです。