Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simultaneous rendering of a template hangs the process #39

Open
elado opened this issue Jun 4, 2015 · 7 comments
Open

Simultaneous rendering of a template hangs the process #39

elado opened this issue Jun 4, 2015 · 7 comments

Comments

@elado
Copy link

elado commented Jun 4, 2015

Looks like rending same compiled template many times simultaneously fires errors like V8::Error: Maximum call stack size exceeded or worse, gets the process stuck.

Is there a better practice for that?
I don't want to lose the speed of compiled templates.

The rendering is running under Sidekiq process which gets stuck often.

require 'celluloid'

handlebars = Handlebars::Context.new
tpl = handlebars.compile(...)

# works fine
10.times { 20.times.map { |i| Celluloid::Future.new { puts "start #{i}"; sleep 0.1; puts "end #{i}" } }.each(&:value) }

# process will hang forever at some point
10.times { 20.times.map { |i| Celluloid::Future.new { puts "start #{i}"; tpl.call(data: data); puts "end #{i}" } }.each(&:value) }
@elado
Copy link
Author

elado commented Jun 4, 2015

I could ask if Handlebars::Context.current has a value and recompile another template. Not optimal though.

@jeremyhaile
Copy link

+1 Just rolled this out and we're seeing Maximum call stack size exceeded. Using a shared context across multiple threads in puma/Rails.

@jeremyhaile
Copy link

@elado I was able to reproduce using your code, but I had to increase the number of "times" significantly to get it to reproduce the issue in a console.

For example, this code reproduces consistently (whereas yours was not):

require 'celluloid'
handlebars = Handlebars::Context.new
tpl = handlebars.compile('Test {{test}}')

# works fine
100.times { 20.times.map { |i| Celluloid::Future.new { puts "start #{i}"; sleep 0.1; puts "end #{i}" } }.each(&:value) }

# process will hang forever at some point
100.times { 20.times.map { |i| Celluloid::Future.new { puts "start #{i}"; tpl.call(test: 123); puts "end #{i}" } }.each(&:value) }

@jeremyhaile
Copy link

I thought that perhaps the handlebars context was not threadsafe. So I tried creating a new handlebars context for each thread. This also seems to completely lock up the process.

Here is a test case that reproduces for me. @elado can you confirm this reproduces for you too?

require 'celluloid'
100.times { 20.times.map { |i| Celluloid::Future.new { puts "start #{i}"; Handlebars::Context.new.compile("Test {{test}}").call(test: 123); puts "end #{i}" } }.each(&:value) }

Any known workarounds here? This is a critical production issue for us.

@elado
Copy link
Author

elado commented Jul 15, 2015

@jeremyhaile
https://github.com/cowboyd/handlebars.rb/blob/master/lib/handlebars/template.rb
the context is being saved globally, I believe that's the issue.

I ended up migrating to ERB. With compiled ERB, performance was pretty good anyway.

@jeremyhaile
Copy link

@elado yeah, I switched to liquid.

@omenking
Copy link

omenking commented May 28, 2018

I am experiencing this issue as well, I have my ruby gem called monster-queries where I used handlebars to intermix SQL queries together. It only became an evident problem when using puma a new version of Rails and Ruby. I might have to migrate away from handlebar unless I successful doing some deep digging on this issue.

I'm considering moving over to https://github.com/jamesotron/FlavourSaver or Liquid templates

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants