Start a child process in a different ruby version

541 views Asked by At

I am using daemon kit to start a background ruby process that listens for Amazon SQS messages. Once a message is received then it starts an child process with Open3.popen3 that needs to run in JRuby.

The background process needs to run in MRI since daemon kit uses Process.daemon to daemonize the process. But so far I haven't been able to force the child process to run in JRuby.

I am using rbenv to manage ruby versions so at first I thought this would work:

Open3.popen3({"RUBY_VERSION" => "jruby-1.7.8"}, "rp5 run /path/to/sketch.rb") do |stdin, stdout, stderr, wait_thr|
  # read stderr and stdout for status and error information ....
end

But in the child process output I was getting the error: "rbenv: jruby: command not found"

Then I tracked how the rbenv runs it's executables so that I could bypass rbenv and run directly the rp5 executable in JRuby.

I first found the rp5 executable in the folder: ~/.rbenv/versions/jruby-1.7.8/bin/rp5

#!/Users/fede/.rbenv/versions/jruby-1.7.8/bin/jruby
#
# This file was generated by RubyGems.
#
# The application 'ruby-processing' is installed as part of a gem, and
# this file is here to facilitate running it.
#

require 'rubygems'

version = ">= 0"

if ARGV.first
  str = ARGV.first
  str = str.dup.force_encoding("BINARY") if str.respond_to? :force_encoding
  if str =~ /\A_(.*)_\z/
    version = $1
    ARGV.shift
  end
end

gem 'ruby-processing', version
load Gem.bin_path('ruby-processing', 'rp5', version)

Then I executed the Gem.bin_path method to find which rp5 executable it was calling. Which is inside the gem: ~/.rbenv/versions/jruby-1.7.8/lib/ruby/gems/shared/gems/ruby-processing-2.3.1/bin/rp5 And then I tried running the child process by calling this rp5 executable directly:

Open3.popen3("~/.rbenv/versions/jruby-1.7.8/lib/ruby/gems/shared/gems/ruby-processing-2.3.1/bin/rp5 run path/to/sketch.rb") do |stdin, stdout, stderr, wait_thr|
  # read stderr and stdout for status and error information ....
end

But I was still getting the same "jruby command not found" error.

And then I inspected that executable:

#!/usr/bin/env ruby

file = __FILE__
if test(?l, file)
  require "pathname"
  file = Pathname.new(file).realpath
end

require File.expand_path(File.dirname(file) + "/../lib/ruby-processing")
Processing::Runner.execute

So does the shebang at the top means that this executable is using the default ruby version?

Is it even possible to launch a child process in an entirely different ruby version?

Thanks.

3

There are 3 answers

0
kares On

have you tried "forcing" it to run in the interpreter by simply running ruby -S e.g. :

Open3.popen3("/usr/bin/ruby ~/.rbenv/versions/jruby-1.7.8/lib/ruby/gems/shared/gems/ruby-processing-2.3.1/bin/rp5 run path/to/sketch.rb") do |stdin, stdout, stderr, wait_thr|
  # ...
end

so first find out where the MRI ruby executable is located and than use that instead of /usr/bin/ruby that should simply do what you're looking for ...

0
onetwopunch On

This is incorrect because of the '~' character for home. You need to explicitly convert ~ to an absolute path.

if your ~ is /home/username/ then:

Open3.popen3("/home/username/.rbenv/versions/jruby-1.7.8/lib/ruby/gems/shared/gems/ruby-processing-2.3.1/bin/rp5 run path/to/sketch.rb") do |stdin, stdout, stderr, wait_thr|
  # read stderr and stdout for status and error information ....
end
0
fedegl On

Thanks for your answers. At the end it was just a matter of setting up the correct ENV variables.

This were the ENV variables that I had to change.

  1. rbenv uses RBENV_VERSION variable, the RUBY_VERSION variable is deprecated.
  2. the environment where I was launching the process didn't even have the PATH to the rbenv shims directory.
  3. The process I was trying to launch was dependent on bundling the gems in a Gemfile, and so I also had to set the BUNDLE_GEMFILE env variable to the path of my Gemfile.