lib/heroku/scalr/app.rb in heroku-scalr-0.2.4 vs lib/heroku/scalr/app.rb in heroku-scalr-0.3.0

- old
+ new

@@ -7,16 +7,17 @@ wait_low: 10, wait_high: 100, ping_low: 200, ping_high: 500, metric: :ping, - min_frequency: 60 + cool_freq: 180, + heat_freq: 60, }.freeze attr_reader :name, :url, :api_key, :interval, :min_dynos, :max_dynos, :metric, :wait_low, :wait_high, :ping_low, :ping_high, - :min_frequency, :last_scaled_at + :cool_freq, :heat_freq, :last_scaled_at # @param [String] name Heroku app name # @param [Hash] opts options # @option opts [Integer] :interval # perform checks every `interval` seconds, default: 60 @@ -26,12 +27,18 @@ # the maximum number of dynos, default: 2 # @option opts [Integer] :wait_low # lowers the number of dynos if queue wait time is less than `wait_low` ms, default: 10 # @option opts [Integer] :wait_high # lowers the number of dynos if queue wait time is more than `wait_high` ms, default: 100 - # @option opts [Integer] :min_frequency - # leave at least `min_frequency` seconds before scaling again, default: 60 + # @option opts [Integer] :ping_low + # lowers the number of dynos if ping time is less than `ping_low` ms, default: 200 + # @option opts [Integer] :ping_high + # lowers the number of dynos if ping time is more than `ping_high` ms, default: 500 + # @option opts [Integer] :cool_freq + # leave at least `cool_freq` seconds before scaling down again, default: 180 + # @option opts [Integer] :heat_freq + # leave at least `heat_freq` seconds before scaling up again, default: 60 # @option opts [String] :api_key # the Heroku account's API key def initialize(name, opts = {}) @name = name.to_s @@ -49,24 +56,26 @@ @wait_low = opts[:wait_low].to_i @wait_high = opts[:wait_high].to_i @ping_low = opts[:ping_low].to_i @ping_high = opts[:ping_high].to_i @metric = Heroku::Scalr::Metric.new(opts[:metric], self) - @min_frequency = opts[:min_frequency].to_i + @cool_freq = opts[:cool_freq].to_i + @heat_freq = opts[:heat_freq].to_i @last_scaled_at = Time.at(0) end # Scales the app def scale! - scale_at = next_scale_attempt + scale_at = last_scaled_at + [cool_freq, heat_freq].min now = Time.now if now < scale_at log :debug, "skip check, next attempt in #{(scale_at - now).to_i}s" return end - do_scale(metric.by) + by = metric.by + do_scale(by) if must_scale?(by, now) rescue => e msg = "#{e.class}: #{e.to_s}" msg << "\n\t" << e.backtrace.join("\n\t") if e.backtrace log :error, msg nil @@ -78,18 +87,28 @@ Heroku::Scalr.logger.send(level, "[#{name}] #{message}") end protected + def must_scale?(by, now) + scale_dn = last_scaled_at + cool_freq + scale_up = last_scaled_at + heat_freq - # @return [Time] the next scale attempt - def next_scale_attempt - last_scaled_at + min_frequency + if by < 0 && now < scale_dn + log :debug, "skip scaling, next down attempt in #{(scale_dn - now).to_i}s" + return false + elsif by > 0 && now < scale_up + log :debug, "skip scaling, next up attempt in #{(scale_up - now).to_i}s" + return false + elsif by == 0 + log :debug, "no scaling required" + return false + end + + true end def do_scale(by) - return if by.zero? - api = Heroku::API.new(api_key: api_key) info = api.get_app(name) unless info.status == 200 log :warn, "error fetching app info, responded with #{info.status}" return \ No newline at end of file