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