Class: Alicorn::Scaler
- Inherits:
-
Object
- Object
- Alicorn::Scaler
- Defined in:
- lib/alicorn/scaler.rb
Instance Attribute Summary collapse
-
#app_name ⇒ Object
Returns the value of attribute app_name.
-
#buffer ⇒ Object
Returns the value of attribute buffer.
-
#delay ⇒ Object
Returns the value of attribute delay.
-
#dry_run ⇒ Object
Returns the value of attribute dry_run.
-
#listener_address ⇒ Object
Returns the value of attribute listener_address.
-
#listener_type ⇒ Object
Returns the value of attribute listener_type.
-
#logger ⇒ Object
Returns the value of attribute logger.
-
#max_workers ⇒ Object
Returns the value of attribute max_workers.
-
#min_workers ⇒ Object
Returns the value of attribute min_workers.
-
#sample_count ⇒ Object
Returns the value of attribute sample_count.
-
#signal_delay ⇒ Object
readonly
Returns the value of attribute signal_delay.
-
#target_ratio ⇒ Object
Returns the value of attribute target_ratio.
Instance Method Summary collapse
- #auto_scale(data, worker_count) ⇒ Object
-
#initialize(options = {}) ⇒ Scaler
constructor
A new instance of Scaler.
- #scale ⇒ Object
Constructor Details
#initialize(options = {}) ⇒ Scaler
Returns a new instance of Scaler.
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
# File 'lib/alicorn/scaler.rb', line 14 def initialize( = {}) @min_workers = [:min_workers] || 1 @max_workers = [:max_workers] @target_ratio = [:target_ratio] || 1.3 @buffer = [:buffer] || 2 @listener_type = [:listener_type] || "tcp" @listener_address = [:listener_address] || "0.0.0.0:80" @delay = [:delay] || 1 @sample_count = [:sample_count] || 30 @app_name = [:app_name] || "unicorn" @dry_run = [:dry_run] @signal_delay = 0.5 log_path = [:log_path] || "/dev/null" self.logger = Logger.new(log_path) logger.level = [:verbose] ? Logger::DEBUG : Logger::WARN end |
Instance Attribute Details
#app_name ⇒ Object
Returns the value of attribute app_name.
8 9 10 |
# File 'lib/alicorn/scaler.rb', line 8 def app_name @app_name end |
#buffer ⇒ Object
Returns the value of attribute buffer.
8 9 10 |
# File 'lib/alicorn/scaler.rb', line 8 def buffer @buffer end |
#delay ⇒ Object
Returns the value of attribute delay.
8 9 10 |
# File 'lib/alicorn/scaler.rb', line 8 def delay @delay end |
#dry_run ⇒ Object
Returns the value of attribute dry_run.
8 9 10 |
# File 'lib/alicorn/scaler.rb', line 8 def dry_run @dry_run end |
#listener_address ⇒ Object
Returns the value of attribute listener_address.
8 9 10 |
# File 'lib/alicorn/scaler.rb', line 8 def listener_address @listener_address end |
#listener_type ⇒ Object
Returns the value of attribute listener_type.
8 9 10 |
# File 'lib/alicorn/scaler.rb', line 8 def listener_type @listener_type end |
#logger ⇒ Object
Returns the value of attribute logger.
8 9 10 |
# File 'lib/alicorn/scaler.rb', line 8 def logger @logger end |
#max_workers ⇒ Object
Returns the value of attribute max_workers.
8 9 10 |
# File 'lib/alicorn/scaler.rb', line 8 def max_workers @max_workers end |
#min_workers ⇒ Object
Returns the value of attribute min_workers.
8 9 10 |
# File 'lib/alicorn/scaler.rb', line 8 def min_workers @min_workers end |
#sample_count ⇒ Object
Returns the value of attribute sample_count.
8 9 10 |
# File 'lib/alicorn/scaler.rb', line 8 def sample_count @sample_count end |
#signal_delay ⇒ Object (readonly)
Returns the value of attribute signal_delay.
12 13 14 |
# File 'lib/alicorn/scaler.rb', line 12 def signal_delay @signal_delay end |
#target_ratio ⇒ Object
Returns the value of attribute target_ratio.
8 9 10 |
# File 'lib/alicorn/scaler.rb', line 8 def target_ratio @target_ratio end |
Instance Method Details
#auto_scale(data, worker_count) ⇒ Object
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
# File 'lib/alicorn/scaler.rb', line 51 def auto_scale(data, worker_count) return nil if data[:active].empty? or data[:queued].empty? connections = data[:active].zip(data[:queued]).map { |e| e.inject(:+) } connections = DataSet.new(connections) # Calculate target target = connections.max * target_ratio + buffer # Check hard thresholds target = max_workers if max_workers and target > max_workers target = min_workers if target < min_workers target = target.ceil logger.debug "target calculated at: #{target}, worker count at #{worker_count}" if worker_count == max_workers and target == max_workers logger.warn "at maximum capacity! cannot scale up" return nil, 0 elsif connections.avg > worker_count and data[:queued].avg > 1 logger.warn "danger, will robinson! scaling up fast!" return "TTIN", target - worker_count elsif target > worker_count logger.debug "scaling up!" return "TTIN", 1 elsif target < worker_count logger.debug "scaling down!" return "TTOU", 1 elsif target == worker_count logger.debug "just right!" return nil, 0 end end |
#scale ⇒ Object
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
# File 'lib/alicorn/scaler.rb', line 32 def scale data = collect_data unicorns = find_unicorns master_pid = find_master_pid(unicorns) worker_count = find_worker_count(unicorns) sig, number = auto_scale(data, worker_count) if sig and !dry_run number.times do send_signal(master_pid, sig) sleep(signal_delay) # Make sure unicorn doesn't discard repeated signals end end rescue StandardError => e logger.error "exception occurred: #{e.class}\n\n#{e.}" raise e unless e.is_a?(AmbiguousMasterError) or e.is_a?(NoMasterError) # Master-related errors are fine, usually just indicate a start or restart end |