Skip to content

Instantly share code, notes, and snippets.

@mindreframer
Last active November 5, 2015 15:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mindreframer/9879200 to your computer and use it in GitHub Desktop.
Save mindreframer/9879200 to your computer and use it in GitHub Desktop.
therubyracer freezes, if used in webservice
##### freezes after a couple of requests...
# OS: osx 10.9.1, libv8 (3.16.14.3 x86_64-darwin-13), therubyracer (0.12.1)
# gem install sinatra therubyracer json puma
# rackup sinatra-nodejs.ru
# wrk -t 2 -d 3 http://0.0.0.0:9292/am
# webserver (puma/webrick) does not make any difference
require 'sinatra/base'
require 'json'
require 'v8'
SUGGESTIONS = []
File.foreach("/usr/share/dict/words") do |line|
SUGGESTIONS << line
break if SUGGESTIONS.size > 200
end
class HelloWord < Sinatra::Base
get '/:q' do
matches = get_matches(params[:q])
halt 200, {'Content-Type' => 'text/json'}, matches.to_json
end
def get_matches(q)
matches = nil
with_proper_vm_lock do
ctx = V8::Context.new
ctx['suggestions'] = SUGGESTIONS
ctx['q'] = q
matches = Array(ctx.eval(<<-eojs
suggestions.filter(function(suggestion) {
return suggestion.search(q) > -1;
}).slice(0,10);
eojs
))
ctx.dispose()
end
matches
end
def with_proper_vm_lock
V8::C::Locker() do
V8::C::HandleScope() do
@cxt = V8::C::Context::New()
begin
@cxt.Enter()
yield
ensure
@cxt.Exit()
end
end
end
end
end
run HelloWord
##### v.2, with connection_pool.... still freezes.
##### freezes after a couple of requests...
# gem install sinatra therubyracer json puma
# rackup sinatra-v8-connection-pool.ru
# wrk -t 2 -d 3 http://0.0.0.0:9292/am
# webserver (puma/webrick) does not make any difference
require 'sinatra/base'
require 'json'
require 'connection_pool'
require 'v8'
require 'execjs'
SUGGESTIONS = []
File.foreach("/usr/share/dict/words") do |line|
SUGGESTIONS << line
break if SUGGESTIONS.size > 200
end
class Renderer
class << self
attr_accessor :pool
def setup!
@pool.shutdown{} if @pool
@pool = ConnectionPool.new(:size => 10, :timeout => 20) { self.new }
end
def render(q)
@pool.with do |renderer|
renderer.render(q)
end
end
end
def context
@context ||= ExecJS.compile('1+1')
end
def render(q)
jscode = <<-JS
function() {
var q = '#{q}';
var suggestions = #{SUGGESTIONS.to_json}
return suggestions.filter(function(suggestion) {
return suggestion.search(q) > -1;
}).slice(0,10);
}()
JS
context.eval(jscode)
rescue ExecJS::ProgramError => e
"[Renderer] #{e.message}"
end
end
Renderer.setup!
class HelloWord < Sinatra::Base
get '/:q' do
matches = get_matches(params[:q])
halt 200, {'Content-Type' => 'text/json'}, matches.to_json
end
def get_matches(q)
Renderer.render(q)
end
end
run HelloWord
@rogsmith
Copy link

rogsmith commented Nov 5, 2015

Did you make any headway figuring out why? I am wanting to do something similar on running js on the server and trying to decide between just using node directly or therubyracer within sinatra/rails. Also considered elixir, but it doesn't have the power of therubyracer.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment