diff --git a/lib/hanami/cli/commands/app/assets/command.rb b/lib/hanami/cli/commands/app/assets/command.rb index 669cfe68..77fa7fcd 100644 --- a/lib/hanami/cli/commands/app/assets/command.rb +++ b/lib/hanami/cli/commands/app/assets/command.rb @@ -11,8 +11,8 @@ module App module Assets # Base class for assets commands. # - # Finds slices with assets present (anything in an `assets/` dir), then forks a child - # process for each slice to run the assets command (`config/assets.js`) for the slice. + # Finds slices with assets present (anything in an `assets/` dir), then spawns a thread + # for each slice to run the assets command (`config/assets.js`) for the slice. # # Prefers the slice's own `config/assets.js` if present, otherwise falls back to the # app-level file. @@ -58,15 +58,13 @@ def call(**) end end - pids = slices_with_assets.map { |slice| fork_child_assets_command(slice) } + threads = slices_with_assets.map { |slice| spawn_assets_thread(slice) } Signal.trap("INT") do - pids.each do |pid| - Process.kill("INT", pid) - end + threads.each(&:kill) end - Process.waitall + threads.each(&:join) end private @@ -81,8 +79,8 @@ def call(**) # @since 2.1.0 # @api private - def fork_child_assets_command(slice) - Process.fork do + def spawn_assets_thread(slice) + Thread.new do cmd, *args = assets_command(slice) system_call.call(cmd, *args, out_prefix: "[#{slice.slice_name}] ") rescue Interrupt diff --git a/spec/unit/hanami/cli/commands/app/assets/compile_spec.rb b/spec/unit/hanami/cli/commands/app/assets/compile_spec.rb index 9edfde26..bc80e8bf 100644 --- a/spec/unit/hanami/cli/commands/app/assets/compile_spec.rb +++ b/spec/unit/hanami/cli/commands/app/assets/compile_spec.rb @@ -33,11 +33,14 @@ class App < Hanami::App end end + let(:thread_double) { double("Thread", kill: nil, join: nil) } + before do - # Instead of forking a process per slice, run that code directly. This is is necessary becuase - # RSpec method expectations won't work on objects in a forked process. - allow(Process).to receive(:fork).and_wrap_original do |_original_method, &block| + # Instead of spawning a thread per slice, run that code directly. This is necessary because + # RSpec method expectations won't work on objects in a different thread. + allow(Thread).to receive(:new).and_wrap_original do |_original_method, &block| block.call + thread_double end end diff --git a/spec/unit/hanami/cli/commands/app/assets/watch_spec.rb b/spec/unit/hanami/cli/commands/app/assets/watch_spec.rb index a9035d16..360f28ed 100644 --- a/spec/unit/hanami/cli/commands/app/assets/watch_spec.rb +++ b/spec/unit/hanami/cli/commands/app/assets/watch_spec.rb @@ -32,11 +32,14 @@ class App < Hanami::App end end + let(:thread_double) { double("Thread", kill: nil, join: nil) } + before do - # Instead of forking a process per slice, run that code directly. This is is necessary becuase - # RSpec method expectations won't work on objects in a forked process. - allow(Process).to receive(:fork).and_wrap_original do |_original_method, &block| + # Instead of spawning a thread per slice, run that code directly. This is necessary because + # RSpec method expectations won't work on objects in a different thread. + allow(Thread).to receive(:new).and_wrap_original do |_original_method, &block| block.call + thread_double end end