Posted by boneill42
on November 30, 2011 at 11:28 AM PST
JSR223 is great if you need to be able to run scripts written in different languages, but you may need to drop below the API if you want concurrency. (at least I had to)
Last night, I was finishing up the map/reduce capabilities within Virgil . We hope to allow people to post ruby scripts that will then get executed over a column family in Cassandra using map/reduce. To do that, we needed concurrent use of a ScriptEngine that could evaluate the ruby script. In the below code snippets, script is a String that contains the contents of a ruby file with a method definition for foo.
First, I started with JSR 223 and the ScriptEngine with the following code:
public static final ScriptEngine ENGINE = new ScriptEngineManager().getEngineByName("jruby");
ScriptContext context = new SimpleScriptContext();
Bindings bindings = context.getBindings(ScriptContext.ENGINE_SCOPE);
That worked fine in unit testing, but when used within map/reduce I encountered a dead-lock of sorts. After some googling, I landed in the Redbridge documentation
. There I found that jruby exposes a lower-level API (beneath JSR223) that exposes concurrent processing features. I swapped the above code, for the following:
this.rubyContainer = new ScriptingContainer(LocalContextScope.CONCURRENT);
this.rubyReceiver = rubyContainer.runScriptlet(script);
container.callMethod(rubyReceiver, "foo", "value");
That let me leverage a single engine for multiple concurrent invocations of the method foo, which is defined in the ruby script.
This worked like a charm.