Skip to content

Commit fe9731e

Browse files
committed
Merge pull request rails#6407 from pinetops/565c1b0a0772ac6cf91c77e9285806f7b028614c
Template concurrency fixes
2 parents 6ef9fda + 565c1b0 commit fe9731e

File tree

1 file changed

+22
-10
lines changed

1 file changed

+22
-10
lines changed

actionpack/lib/action_view/template.rb

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
require 'active_support/core_ext/object/blank'
33
require 'active_support/core_ext/object/try'
44
require 'active_support/core_ext/kernel/singleton_class'
5+
require 'thread'
56

67
module ActionView
78
# = Action View Template
@@ -123,6 +124,7 @@ def initialize(source, identifier, handler, details)
123124
@virtual_path = details[:virtual_path]
124125
@updated_at = details[:updated_at] || Time.now
125126
@formats = Array.wrap(format).map { |f| f.is_a?(Mime::Type) ? f.ref : f }
127+
@compile_mutex = Mutex.new
126128
end
127129

128130
# Returns if the underlying handler supports streaming. If so,
@@ -224,18 +226,28 @@ def encode!
224226
def compile!(view) #:nodoc:
225227
return if @compiled
226228

227-
if view.is_a?(ActionView::CompiledTemplates)
228-
mod = ActionView::CompiledTemplates
229-
else
230-
mod = view.singleton_class
231-
end
229+
# Templates can be used concurrently in threaded environments
230+
# so compilation and any instance variable modification must
231+
# be synchronized
232+
@compile_mutex.synchronize do
233+
# Any thread holding this lock will be compiling the template needed
234+
# by the threads waiting. So re-check the @compiled flag to avoid
235+
# re-compilation
236+
return if @compiled
237+
238+
if view.is_a?(ActionView::CompiledTemplates)
239+
mod = ActionView::CompiledTemplates
240+
else
241+
mod = view.singleton_class
242+
end
232243

233-
compile(view, mod)
244+
compile(view, mod)
234245

235-
# Just discard the source if we have a virtual path. This
236-
# means we can get the template back.
237-
@source = nil if @virtual_path
238-
@compiled = true
246+
# Just discard the source if we have a virtual path. This
247+
# means we can get the template back.
248+
@source = nil if @virtual_path
249+
@compiled = true
250+
end
239251
end
240252

241253
# Among other things, this method is responsible for properly setting

0 commit comments

Comments
 (0)