Ylan Segal

Faster Rspec: jRuby, Spork, Nailgun and Bundler Binstubs

I recently discovered that bundler has a feature to create binstubs, so I decided to redo my benchmarks of running a single pending spec (but including the complete spec_helper for my project).

To create rspec binstubs:

1
$ bundle binstubs rspec-core

Here are my findings:

Description Command Avg. Time (3 runs)
Bundled Rspec bundle exec rspec 61.76 s
Binstubs bin/rspec 50.24 s
Binstubs + Spork bin/rspec –drb 17.43 s
Binstubs + Spork + Nailgun jruby –ng -S bin/rspec –drb 6.65 s

It is still slower than I would like, but well worth the effort. Since I didn’t want to remember the specific invocation depending on what I have running, I have a script that will use binstubs, nailgun and/or spork if available:

smart_rspec
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#! /bin/bash

# Looking for binstubs
if [ -f ./bin/rspec ]; then
  RSPEC="bin/rspec"
else
  RSPEC="bundle exec rspec"
fi

NAILGUN_PORT=2113
SPORK_PORT=8989

# Looking for nailgun
lsof -i :$NAILGUN_PORT > /dev/null
if [ $? == 0 ]; then
  RSPEC="jruby --ng -S $RSPEC"
fi

# Looking for spork
lsof -i :$SPORK_PORT > /dev/null
if [ $? == 0 ]; then
  RSPEC="$RSPEC --drb"
fi

CMD="$RSPEC $@"
echo $CMD
$CMD

A Tale of jRuby Profiling

Recently, I have been working on moving some processes from the request-response web cycle to a MongoMapper-backed Delayed::Job. Everything seem to go smoothly, but it seemed that there was some slowness actually queuing the jobs. Here is how I got to the bottom of it.

Sandi Metz' Rules

Sandi Metz recently was a guest at a Ruby Rouges Podcast to discuss her book Practical Object Oriented Design In Ruby, which I reviewed. I encourage you to listen to the episode.

During the interview, she mentioned some rules that she had come up with to give when asked about design guidelines. She was clear that the rules could be broken, but once you understand why the rules are there in the first place.

Without further ado:

  1. Your class can be no longer than 100 lines of code
  2. Your methods can be no longer than 5 lines of code
  3. You can pass no more than 4 parameters, and you can’t just make it one big hash
  4. Your controller can only instantiate 1 object to do what needs to be done
  5. Your view can only know about 1 instance variable

List Open Files With Lsof

In the UNIX paradigm, everything is a file system. So, it makes sense that there is a utility to work with open files.

A common use case is to try to eject a mounted drive or clear the trash and get a warning about a locked file. What process has this file or folder open?

1
2
3
$ lsof /Volumes/Personal/blog/source/_posts
COMMAND     PID      USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
Sublime   13472 ylansegal  cwd    DIR   14,7      442 6072 /Volumes/Personal/blog/source/_posts

Since everything is a file, it works just as well with ports:

1
2
3
$ lsof -i :4000
COMMAND   PID      USER   FD   TYPE             DEVICE SIZE/OFF NODE NAME
ruby    20740 ylansegal    7u  IPv4 0xffffff80158d6de0      0t0  TCP *:terabase (LISTEN)

Or you can check the files for a specific program:

1
2
3
4
5
6
7
8
9
10
11
$  lsof -p 21286
COMMAND   PID      USER   FD     TYPE DEVICE  SIZE/OFF    NODE NAME
tail    21286 ylansegal  cwd      DIR   14,7       850      28 /Volumes/Personal/blog
tail    21286 ylansegal  txt      REG   14,4     57488    9770 /usr/bin/tail
tail    21286 ylansegal  txt      REG   14,4    599280    8989 /usr/lib/dyld
tail    21286 ylansegal  txt      REG   14,4 299110400 3283993 /private/var/db/dyld/dyld_shared_cache_x86_64
tail    21286 ylansegal    0u     CHR   16,1  0t238994     723 /dev/ttys001
tail    21286 ylansegal    1u     CHR   16,1  0t238994     723 /dev/ttys001
tail    21286 ylansegal    2u     CHR   16,1  0t238994     723 /dev/ttys001
tail    21286 ylansegal    3r     REG   14,7      1450     240 /Volumes/Personal/blog/Gemfile.lock
tail    21286 ylansegal    4u  KQUEUE                          count=0, state=0x2

lsof supports many, many options, read the man pages for more information.