Ruby via the backdoor…

At work, our team does not do much development – we support a third party’s product.  Most work is around the edges, integrating it with the rest of the systems.

Some of that work is in Java, but recently I had a chance to sneak in a little Ruby (or  JRuby to be specific).

Why Ruby/JRuby? To me, the main reason is that its a more succinct way of expressing the program logic and combined with the JVM integration features of JRuby, it was an obvious choice.

The premise was we wanted to make the extension of a component flexible/scriptable and ruby seemed like a good fit.

Here are some of the highlights of what was done…

The requirement was to publish data from one source to a webservice.

The initial cut was a pipeline of classes that transformed the source data into target format and then calling the webservice. The problem with this solution was that the webservice was very slow – only able to handle around 16 calls per second – compared to the 100 messages per second that were coming from the source.

This was addressed by adding some threading via calling out to Java’s concurrent utilities

A threadpool was created (num_threads specifies number of threads to run):


@exec = java.util.concurrent.Executors.new_fixed_thread_pool $props["im.num_threads"].to_i

And then for each message that came in, its handling is passed to the threadpool

@exec.execute do
... # do work, happens in a separate thread
end

This meant we could hammer the webservice with a lot more calls, however the downside is that we need to be wary of concurrent issues.

Some of the processes in the pipeline were completely standalone and so were wrapped in Java ThreadLocal objects.

@time_formatter = $jruby_obj.threadLocal { FormatTime.new }

Where the process was not standalone, but had shared data structures, then a mutex was used to ensure only one process accessed the structure at a time.

# create the mutex object - once for the shared object
@mutex = Mutex.new
...

# then when we need to control access to some data we do this
@mutex.synchronize do
...
end

Now, by specifying 20-30 threads, were do 100+ calls per second to the webservice :)