Class: EcsDeploy::AutoScaler::ServiceConfig

Inherits:
Struct
  • Object
show all
Extended by:
ConfigBase::ClassMethods
Includes:
ConfigBase
Defined in:
lib/ecs_deploy/auto_scaler.rb

Instance Method Summary collapse

Methods included from ConfigBase::ClassMethods

client_table

Constructor Details

#initialize(attributes = {}) ⇒ ServiceConfig

Returns a new instance of ServiceConfig.



109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
# File 'lib/ecs_deploy/auto_scaler.rb', line 109

def initialize(attributes = {})
  super(attributes)
  self.idle_time ||= 60
  self.max_task_count = Array(max_task_count)
  self.upscale_triggers = upscale_triggers.to_a.map do |t|
    TriggerConfig.new(t.merge(region: region))
  end
  self.downscale_triggers = downscale_triggers.to_a.map do |t|
    TriggerConfig.new(t.merge(region: region))
  end
  self.max_task_count.sort!
  self.desired_count = fetch_service.desired_count
  @reach_max_at = nil
  @last_updated_at = nil
end

Instance Method Details

#client ⇒ Object



125
126
127
128
129
130
131
# File 'lib/ecs_deploy/auto_scaler.rb', line 125

def client
  self.class.client_table[region] ||= Aws::ECS::Client.new(
    access_key_id: EcsDeploy.config.access_key_id,
    secret_access_key: EcsDeploy.config.secret_access_key,
    region: region
  )
end

#current_min_task_count ⇒ Object



138
139
140
141
142
143
144
145
146
# File 'lib/ecs_deploy/auto_scaler.rb', line 138

def current_min_task_count
  return min_task_count if scheduled_min_task_count.nil? || scheduled_min_task_count.empty?

  scheduled_min_task_count.find(-> { {"count" => min_task_count} }) { |s|
    from = Time.parse(s["from"])
    to = Time.parse(s["to"])
    (from..to).cover?(Time.now)
  }["count"]
end

#fetch_service ⇒ Object



153
154
155
156
157
158
159
160
# File 'lib/ecs_deploy/auto_scaler.rb', line 153

def fetch_service
  res = client.describe_services(cluster: cluster, services: [name])
  raise "Service \"#{name}\" is not found" if res.services.empty?
  res.services[0]
rescue => e
  AutoScaler.error_logger.error(e)
  self.class.client_table[region] = nil
end

#idle? ⇒ Boolean

Returns:

  • (Boolean)


133
134
135
136
# File 'lib/ecs_deploy/auto_scaler.rb', line 133

def idle?
  return false unless @last_updated_at
  (Time.now - @last_updated_at) < idle_time
end

#overheat? ⇒ Boolean

Returns:

  • (Boolean)


148
149
150
151
# File 'lib/ecs_deploy/auto_scaler.rb', line 148

def overheat?
  return false unless @reach_max_at
  (Time.now - @reach_max_at) > cooldown_time_for_reach_max
end

#update_service(next_desired_count) ⇒ Object



162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
# File 'lib/ecs_deploy/auto_scaler.rb', line 162

def update_service(next_desired_count)
  current_level = max_task_level(desired_count)
  next_level = max_task_level(next_desired_count)
  if current_level < next_level && overheat? # next max
    level = next_level
    @reach_max_at = nil
    AutoScaler.logger.info "Service \"#{name}\" is overheat, uses next max count"
  elsif current_level < next_level && !overheat? # wait cooldown
    level = current_level
    @reach_max_at ||= Time.now
    AutoScaler.logger.info "Service \"#{name}\" waits cooldown in #{(Time.now - @reach_max_at).to_i}sec"
  elsif current_level == next_level && next_desired_count >= max_task_count[current_level] # reach current max
    level = current_level
    @reach_max_at ||= Time.now
    AutoScaler.logger.info "Service \"#{name}\" waits cooldown in #{(Time.now - @reach_max_at).to_i}sec"
  elsif current_level == next_level && next_desired_count < max_task_count[current_level]
    level = current_level
    @reach_max_at = nil
    AutoScaler.logger.info "Service \"#{name}\" clears cooldown state"
  elsif current_level > next_level
    level = next_level
    @reach_max_at = nil
    AutoScaler.logger.info "Service \"#{name}\" clears cooldown state"
  end

  next_desired_count = [next_desired_count, max_task_count[level]].min
  client.update_service(
    cluster: cluster,
    service: name,
    desired_count: next_desired_count,
  )
  @last_updated_at = Time.now
  self.desired_count = next_desired_count
  AutoScaler.logger.info "Update service \"#{name}\": desired_count -> #{next_desired_count}"
rescue => e
  AutoScaler.error_logger.error(e)
  self.class.client_table[region] = nil
end