Skip to content

Commit af90662

Browse files
authored
Merge pull request #469 from wjordan/concurrent_asset_compile
Concurrent asset compile
2 parents e640ce1 + 4366cc6 commit af90662

File tree

2 files changed

+80
-10
lines changed

2 files changed

+80
-10
lines changed

lib/sprockets/manifest.rb

+10-9
Original file line numberDiff line numberDiff line change
@@ -120,11 +120,14 @@ def find(*args)
120120
return to_enum(__method__, *args) unless block_given?
121121

122122
environment = self.environment.cached
123-
args.flatten.each do |path|
124-
environment.find_all_linked_assets(path) do |asset|
125-
yield asset
123+
promises = args.flatten.map do |path|
124+
Concurrent::Promise.execute(executor: executor) do
125+
environment.find_all_linked_assets(path) do |asset|
126+
yield asset
127+
end
126128
end
127129
end
130+
promises.each(&:wait!)
128131

129132
nil
130133
end
@@ -160,7 +163,6 @@ def compile(*args)
160163

161164
filenames = []
162165
concurrent_exporters = []
163-
executor = Concurrent::FixedThreadPool.new(Concurrent.processor_count)
164166

165167
find(*args) do |asset|
166168
mtime = Time.now.iso8601
@@ -183,11 +185,6 @@ def compile(*args)
183185
exporters_for_asset(asset) do |exporter|
184186
next if exporter.skip?(logger)
185187

186-
if !environment.export_concurrent
187-
exporter.call
188-
next
189-
end
190-
191188
if promise.nil?
192189
promise = Concurrent::Promise.new(executor: executor) { exporter.call }
193190
concurrent_exporters << promise.execute
@@ -327,5 +324,9 @@ def logger
327324
logger
328325
end
329326
end
327+
328+
def executor
329+
@executor ||= environment.export_concurrent ? :fast : :immediate
330+
end
330331
end
331332
end

test/test_manifest.rb

+70-1
Original file line numberDiff line numberDiff line change
@@ -505,7 +505,7 @@ def teardown
505505
manifest = Sprockets::Manifest.new(@env, @dir)
506506

507507
result = manifest.find_sources("mobile/a.js", "mobile/b.js")
508-
assert_equal ["var A;\n", "var B;\n"], result.to_a
508+
assert_equal ["var A;\n", "var B;\n"], result.to_a.sort
509509
end
510510

511511
test "find_sources without environment" do
@@ -571,4 +571,73 @@ def teardown
571571
assert_equal 'kaboom', ex.message
572572
end
573573
end
574+
575+
# Sleep duration to context switch between concurrent threads.
576+
CONTEXT_SWITCH_DURATION = 0.1
577+
578+
# Record Exporter sequence with a delay to test concurrency.
579+
class SlowExporter < Sprockets::Exporters::Base
580+
class << self
581+
attr_accessor :seq
582+
end
583+
584+
def call
585+
SlowExporter.seq << '0'
586+
sleep CONTEXT_SWITCH_DURATION
587+
SlowExporter.seq << '1'
588+
end
589+
end
590+
591+
class SlowExporter2 < SlowExporter
592+
end
593+
594+
test 'concurrent exporting' do
595+
# Register 2 exporters and compile 2 files to ensure that
596+
# all 4 exporting tasks run concurrently.
597+
SlowExporter.seq = []
598+
@env.register_exporter 'image/png',SlowExporter
599+
@env.register_exporter 'image/png',SlowExporter2
600+
Sprockets::Manifest.new(@env, @dir).compile('logo.png', 'troll.png')
601+
assert_equal %w(0 0 0 0 1 1 1 1), SlowExporter.seq
602+
end
603+
604+
test 'sequential exporting' do
605+
@env.export_concurrent = false
606+
SlowExporter.seq = []
607+
@env.register_exporter 'image/png',SlowExporter
608+
@env.register_exporter 'image/png',SlowExporter2
609+
Sprockets::Manifest.new(@env, @dir).compile('logo.png', 'troll.png')
610+
assert_equal %w(0 1 0 1 0 1 0 1), SlowExporter.seq
611+
end
612+
613+
# Record Processor sequence with a delay to test concurrency.
614+
class SlowProcessor
615+
attr_reader :seq
616+
617+
def initialize
618+
@seq = []
619+
end
620+
621+
def call(_)
622+
seq << '0'
623+
sleep CONTEXT_SWITCH_DURATION
624+
seq << '1'
625+
nil
626+
end
627+
end
628+
629+
test 'concurrent processing' do
630+
processor = SlowProcessor.new
631+
@env.register_postprocessor 'image/png', processor
632+
Sprockets::Manifest.new(@env, @dir).compile('logo.png', 'troll.png')
633+
assert_equal %w(0 0 1 1), processor.seq
634+
end
635+
636+
test 'sequential processing' do
637+
@env.export_concurrent = false
638+
processor = SlowProcessor.new
639+
@env.register_postprocessor 'image/png', processor
640+
Sprockets::Manifest.new(@env, @dir).compile('logo.png', 'troll.png')
641+
assert_equal %w(0 1 0 1), processor.seq
642+
end
574643
end

0 commit comments

Comments
 (0)