diff --git a/example/Procfile b/example/Procfile index 5bb6e13..d6451a9 100644 --- a/example/Procfile +++ b/example/Procfile @@ -1,2 +1,2 @@ -ticker ./ticker +ticker ./ticker $PORT error ./error \ No newline at end of file diff --git a/example/ticker b/example/ticker index 3648810..67b6564 100755 --- a/example/ticker +++ b/example/ticker @@ -1,6 +1,6 @@ #!/usr/bin/env ruby while true - puts "tick" + puts "tick: #{ARGV.inspect}" sleep 1 end diff --git a/lib/foreman/cli.rb b/lib/foreman/cli.rb index d38cec7..a311f92 100644 --- a/lib/foreman/cli.rb +++ b/lib/foreman/cli.rb @@ -9,6 +9,7 @@ class Foreman::CLI < Thor desc "start [PROCESS]", "Start the application, or a specific process" + method_option :port, :type => :numeric, :aliases => "-p" method_option :concurrency, :type => :string, :aliases => "-c", :banner => '"alpha=5,bar=3"' diff --git a/lib/foreman/engine.rb b/lib/foreman/engine.rb index 2e1ae18..b664a27 100644 --- a/lib/foreman/engine.rb +++ b/lib/foreman/engine.rb @@ -20,27 +20,14 @@ class Foreman::Engine @directory = File.expand_path(File.dirname(procfile)) end - def processes(concurrency=nil) + def processes @processes ||= begin - concurrency = Foreman::Utils.parse_concurrency(concurrency) - procfile.split("\n").inject({}) do |hash, line| next if line.strip == "" name, command = line.split(" ", 2) - - if concurrency[name] > 1 then - 1.upto(concurrency[name]) do |num| - process = Foreman::Process.new("#{name}.#{num}", command) - process.color = next_color - hash[process.name] = process - end - else - process = Foreman::Process.new(name, command) - process.color = next_color - hash[process.name] = process - end - - hash + process = Foreman::Process.new(name, command) + process.color = next_color + hash.update(process.name => process) end end end @@ -48,8 +35,8 @@ class Foreman::Engine def start(options={}) proctitle "ruby: foreman master" - processes(options[:concurrency]).each do |name, process| - fork process + processes.each do |name, process| + fork process, options end trap("TERM") { kill_and_exit("TERM") } @@ -59,11 +46,7 @@ class Foreman::Engine end def execute(name, options={}) - processes(options[:concurrency]).values.select do |process| - process.name =~ /\A#{name}\.?\d*\Z/ - end.each do |process| - fork process - end + fork processes[name], options trap("TERM") { kill_and_exit("TERM") } trap("INT") { kill_and_exit("INT") } @@ -79,7 +62,17 @@ class Foreman::Engine private ###################################################################### - def fork(process) + def fork(process, options={}) + concurrency = Foreman::Utils.parse_concurrency(options[:concurrency]) + + 1.upto(concurrency[process.name]) do |num| + fork_individual(process, port_for(process, num, options[:port])) + end + end + + def fork_individual(process, port) + ENV["PORT"] = port.to_s + pid = Process.fork do run(process) end @@ -133,8 +126,8 @@ private ###################################################################### end def pad_process_name(process) - name = process ? process.name : "system" - name.ljust(longest_process_name) + name = process ? "#{process.name}:#{ENV["PORT"]}" : "system" + name.ljust(longest_process_name + 6) # add 6 for port padding end def print_info diff --git a/spec/foreman/engine_spec.rb b/spec/foreman/engine_spec.rb index 2526219..0c030a0 100644 --- a/spec/foreman/engine_spec.rb +++ b/spec/foreman/engine_spec.rb @@ -23,17 +23,26 @@ describe "Foreman::Engine" do describe "start" do it "forks the processes" do write_procfile - mock(subject).fork(subject.processes["alpha"]) - mock(subject).fork(subject.processes["bravo"]) + mock(subject).fork(subject.processes["alpha"], {}) + mock(subject).fork(subject.processes["bravo"], {}) mock(subject).watch_for_termination subject.start end + + it "handles concurrency" do + write_procfile + mock(subject).fork_individual(subject.processes["alpha"], 5000) + mock(subject).fork_individual(subject.processes["alpha"], 5001) + mock(subject).fork_individual(subject.processes["bravo"], 5100) + mock(subject).watch_for_termination + subject.start(:concurrency => "alpha=2") + end end describe "execute" do it "runs the processes" do write_procfile - mock(subject).fork(subject.processes["alpha"]) + mock(subject).fork(subject.processes["alpha"], {}) mock(subject).watch_for_termination subject.execute("alpha") end