Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions lib/procodile/cli.rb
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ def dispatch(command)
instances = ControlClient.run(@config.sock_path, 'start_processes', :processes => process_names_from_cli_option, :tag => @options[:tag], :port_allocations => @options[:port_allocations])
if instances.empty?
puts "No processes to start."
report_processes_below_quantity
else
instances.each do |instance|
puts "Started".color(32) + " #{instance['description']} (PID: #{instance['pid']})"
Expand Down Expand Up @@ -475,6 +476,32 @@ def self.pid_active?(pid)
false
end

# `start` only starts process types with no running instances at all (see
# Supervisor#start_processes), so a type running below its configured quantity is
# skipped and the user is told "No processes to start." with no indication that
# anything is wrong. Name the command that actually tops it up.
def report_processes_below_quantity
status = ControlClient.run(@config.sock_path, 'status')
below = processes_below_quantity(status['messages'], process_names_from_cli_option)
return if below.empty?

verb = below.size == 1 ? 'is' : 'are'
puts "#{below.join(', ')} #{verb} running below the configured quantity."
puts "Run `procodile check_concurrency` to start the missing process(es)."
rescue Procodile::Error
# This is advisory output only -- never turn a successful no-op into a failure.
nil
end

# Names of process types that the supervisor reports as below their configured
# quantity, optionally narrowed to the types the user asked to start. Instance
# suffixes ("worker.1") are reduced to the type name.
def processes_below_quantity(messages, requested = nil)
below = messages.select { |m| m['type'] == 'incorrect_quantity' }.map { |m| m['process'] }
return below if requested.nil?
below & requested.map { |name| name.split('.', 2).first }
end

def process_names_from_cli_option
if @options[:processes]
processes = @options[:processes].split(',')
Expand Down
49 changes: 49 additions & 0 deletions spec/specs/cli_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
require 'spec_helper'
require 'procodile/cli'

describe Procodile::CLI do
subject(:cli) { described_class.new }

let(:worker_below) do
{'type' => 'incorrect_quantity', 'process' => 'worker', 'current' => 23, 'desired' => 25}
end

let(:web_below) do
{'type' => 'incorrect_quantity', 'process' => 'web', 'current' => 1, 'desired' => 2}
end

let(:not_running) do
{'type' => 'not_running', 'instance' => 'worker.1', 'status' => 'Failed'}
end

describe "#processes_below_quantity" do
it "returns every under-quantity process when nothing specific was requested" do
result = cli.send(:processes_below_quantity, [worker_below, web_below], nil)
expect(result).to eq(['worker', 'web'])
end

it "ignores messages that are not about quantity" do
result = cli.send(:processes_below_quantity, [not_running], nil)
expect(result).to be_empty
end

it "narrows to the processes the user asked to start" do
result = cli.send(:processes_below_quantity, [worker_below, web_below], ['web'])
expect(result).to eq(['web'])
end

it "matches a requested instance name against its process type" do
result = cli.send(:processes_below_quantity, [worker_below], ['worker.1'])
expect(result).to eq(['worker'])
end

it "returns nothing when the requested process is at its quantity" do
result = cli.send(:processes_below_quantity, [worker_below], ['web'])
expect(result).to be_empty
end

it "returns nothing when there are no messages" do
expect(cli.send(:processes_below_quantity, [], nil)).to be_empty
end
end
end