Building Ruby and JRuby on CircleCi in parallel

Configure CircleCI to build your app on Ruby and JRuby in parallel.

Recently I had to convert a non-trivial Rails app from MRI to JRuby for one of our customers. The process was quite smooth overall, but business requirements change and the client may need to be able to run the app on either MRI or JRuby.

To make sure code changes won’t break on either platform, I configured CircleCI to build both versions at the same time. I decided to manually configure parallelism, so the different platforms build in different containers (MRI in container 0, JRuby in container 1) at the same time.

Environment configuration

The configuration starts with adding some environment variables for specifying the different Ruby versions. I also added a combined RUBY_VERSIONS variable, which is used for running RVM commands on both platforms with rvm do. I also added some Java specific tuning options to make sure the JRuby builds run reasonably fast and don’t consume too much memory.
machine:
  environment:
    MRI_VERSION: 2.3.3
    JRUBY_VERSION: jruby-9.1.6.0
    RUBY_VERSIONS: $MRI_VERSION,$JRUBY_VERSION
    JRUBY_OPTS: '--debug -J-XX:+TieredCompilation -J-XX:TieredStopAtLevel=1 -J-Xms512m -J-Xmx1024m'
    # other environment variables

Dependency installation

This is a simple override for CircleCI’s usual dependency installation: update RVM to get the newest Ruby versions, install the ones specified in RUBY_VERSIONS, then use rvm do to install Bundler and the gems specified in the Gemfile(using platforms it’s fairly easy to build a Gemfile that works for both Ruby versions).
dependencies:
  override:
    - rvm get head
    - rvm install $RUBY_VERSIONS
    - rvm $RUBY_VERSIONS do gem install bundler
    - rvm $RUBY_VERSIONS do bundle install

Test setup

This is a neat trick I picked up from CircleCI’s documentation. You can use a shell case statement inside the configuration to run different commands in different containers. In combination with rvm use this allowed me to “pin” MRI to container 0 and JRuby to container 1, so we immediately know which version failed the build.
test:
  override:
    - case $CIRCLE_NODE_INDEX in 0) rvm use $MRI_VERSION && bundle exec rspec ;; 1) rvm use $JRUBY_VERSION && bundle exec rspec ;; esac:
        parallel: true

Conclusion

While CircleCI in its current form lacks support for something like Travis’ build matrix, it’s flexible enough to allow for workarounds. While I hope that version 2.0 will simplify this process, the current solution is easy enough and works well for our purposes.
Like 105 likes
Michael
Share:

Join the conversation

This will be shown public
All comments are moderated

Get our stories delivered

From us to your inbox weekly.