Module: AdvancedConnection::ActiveRecordExt::ConnectionPool::IdleManager

Extended by:
ActiveSupport::Concern
Defined in:
lib/advanced_connection/active_record_ext/connection_pool/idle_manager.rb

Instance Method Summary collapse

Instance Method Details

#active_connectionsObject



198
199
200
# File 'lib/advanced_connection/active_record_ext/connection_pool/idle_manager.rb', line 198

def active_connections
  @connections.select(&:in_use?)
end

#available_connectionsObject



202
203
204
# File 'lib/advanced_connection/active_record_ext/connection_pool/idle_manager.rb', line 202

def available_connections
  @connections.reject(&:in_use?)
end

#checkin_with_last_checked_in(conn) ⇒ Object



192
193
194
195
196
# File 'lib/advanced_connection/active_record_ext/connection_pool/idle_manager.rb', line 192

def checkin_with_last_checked_in(conn)
  conn.last_checked_in = Time.now
  idle_manager.debug "checking in connection #{conn.object_id} at #{conn.last_checked_in}"
  checkin_without_last_checked_in(conn)
end

#connection_limitObject



188
189
190
# File 'lib/advanced_connection/active_record_ext/connection_pool/idle_manager.rb', line 188

def connection_limit
  @size
end

#create_idle_connectionsObject



265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
# File 'lib/advanced_connection/active_record_ext/connection_pool/idle_manager.rb', line 265

def create_idle_connections
  idle_count = idle_connections.size
  open_slots = connection_limit - @connections.size

  # if we already have enough idle connections, do nothing
  return unless idle_count < min_idle_connections

  # if we don't have enough available slots (i.e., current pool size
  # is greater than max pool size) then do nothing
  return unless open_slots > 0

  # otherwise, spin up connections up to our min_idle_connections setting
  create_count = min_idle_connections - idle_count
  create_count = open_slots if create_count > open_slots

  warmup_connections(create_count)
end

#idle_check_intervalObject



162
163
164
165
166
# File 'lib/advanced_connection/active_record_ext/connection_pool/idle_manager.rb', line 162

def idle_check_interval
  @idle_check_interval ||= (spec.config[:idle_check_interval] || \
                           AdvancedConnection.idle_check_interval || \
                           max_idle_time).to_i
end

#idle_connectionsObject



206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
# File 'lib/advanced_connection/active_record_ext/connection_pool/idle_manager.rb', line 206

def idle_connections
  available_connections.select do |conn|
    (Time.now - conn.last_checked_in).to_f > max_idle_time
  end.sort { |a, b|
    case queue_type
      when :prefer_younger then
        # when prefering younger, we sort oldest->youngest
        # this ensures that older connections will be culled
        # during #remove_idle_connections()
        -(a.instance_age <=> b.instance_age)
      when :prefer_older then
        # when prefering older, we sort youngest->oldest
        # this ensures that younger connections will be culled
        # during #remove_idle_connections()
        (a.instance_age <=> b.instance_age)
      else
        # with fifo / lifo queues, we only care about the
        # last time a given connection was used (inferred
        # by when it was last checked into the pool).
        # This ensures that the longer idling connections
        # will be culled.
        -(a.last_checked_in <=> b.last_checked_in)
    end
  }
end

#initialize_with_advanced_connection(spec) ⇒ Object



129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# File 'lib/advanced_connection/active_record_ext/connection_pool/idle_manager.rb', line 129

def initialize_with_advanced_connection(spec)
  initialize_without_advanced_connection(spec)

  @available = case queue_type
    when :prefer_older   then Queues::OldAgeBiased.new
    when :prefer_younger then Queues::YoungAgeBiased.new
    when :lifo, :stack   then Queues::Stack.new
    when :fifo, :queue   then Queues::FIFO.new
    else
      Rails.logger.warn "Unknown queue_type #{queue_type.inspect} - using standard FIFO instead"
      Queues::FIFO.new
  end

  @idle_manager = IdleManager.new(self, idle_check_interval).tap(&:start)
end

#max_idle_connectionsObject



168
169
170
171
172
173
174
175
176
177
178
# File 'lib/advanced_connection/active_record_ext/connection_pool/idle_manager.rb', line 168

def max_idle_connections
  @max_idle_connections ||= begin
    begin
      (spec.config[:max_idle_connections] || \
        AdvancedConnection.max_idle_connections).to_i
    rescue FloatDomainError => e
      raise unless e.message =~ /infinity/i
      ::Float::INFINITY
    end
  end
end

#max_idle_timeObject



157
158
159
160
# File 'lib/advanced_connection/active_record_ext/connection_pool/idle_manager.rb', line 157

def max_idle_time
  @max_idle_time ||= (spec.config[:max_idle_time] || \
                     AdvancedConnection.max_idle_time).to_i
end

#min_idle_connectionsObject



180
181
182
183
184
185
186
# File 'lib/advanced_connection/active_record_ext/connection_pool/idle_manager.rb', line 180

def min_idle_connections
  @min_idle_connections ||= begin
    min_idle = (spec.config[:min_idle_connections] || AdvancedConnection.min_idle_connections).to_i
    min_idle = (min_idle > 0 ? min_idle : 0)
    min_idle <= max_idle_connections ? min_idle : max_idle_connections
  end
end

#pool_statisticsObject



232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
# File 'lib/advanced_connection/active_record_ext/connection_pool/idle_manager.rb', line 232

def pool_statistics
  idle = active = available = 0
  synchronize do
    idle      = idle_connections.size
    active    = active_connections.size
    available = available_connections.size
  end
  total = active + available

  ActiveSupport::OrderedOptions.new.merge(
    total:     total,
    idle:      idle,
    active:    active,
    available: available
  )
end

#queue_typeObject



145
146
147
148
# File 'lib/advanced_connection/active_record_ext/connection_pool/idle_manager.rb', line 145

def queue_type
  @queue_type ||= spec.config.fetch(:queue_type,
                                    AdvancedConnection.connection_pool_queue_type).to_s.downcase.to_sym
end

#remove_idle_connectionsObject



283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
# File 'lib/advanced_connection/active_record_ext/connection_pool/idle_manager.rb', line 283

def remove_idle_connections
  # don't attempt to remove idle connections if we have threads waiting
  if @available.num_waiting > 0
    idle_manager.log_warn "Cannot reap while threads actively waiting on db connections"
    return
  end

  idle_conns = idle_connections
  idle_count = idle_conns.size

  unless idle_count > max_idle_connections
    idle_manager.log_warn "idle count (#{idle_count}) does not exceed max idle connections (#{max_idle_connections}); skipping reap."
    return
  end

  cull_count = (idle_count - max_idle_connections)

  culled = 0
  idle_conns.each_with_index do |conn, idx|
    if idx < cull_count
      if remove_connection(conn)
        culled += 1
        idle_manager.log_info "culled connection ##{idx} id##{conn.object_id} - age:#{conn.instance_age.to_i} idle_time:#{conn.idle_time.to_i}"
      else
        idle_manager.log_info "kept connection ##{idx} id##{conn.object_id} - age:#{conn.instance_age.to_i} idle_time:#{conn.idle_time.to_i}"
      end
    else
      idle_manager.log_info "kept connection ##{idx} id##{conn.object_id} - age:#{conn.instance_age.to_i} idle_time:#{conn.idle_time.to_i}"
    end
  end

  idle_manager.log_info "culled %d connections" % culled
end

#warmup_connection_countObject



150
151
152
153
154
155
# File 'lib/advanced_connection/active_record_ext/connection_pool/idle_manager.rb', line 150

def warmup_connection_count
  @warmup_connection_count ||= begin
    conns = spec.config[:warmup_connections] || AdvancedConnection.warmup_connections
    conns.to_i > connection_limit ? connection_limit : conns.to_i
  end
end

#warmup_connections(count = nil) ⇒ Object



249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
# File 'lib/advanced_connection/active_record_ext/connection_pool/idle_manager.rb', line 249

def warmup_connections(count = nil)
  count ||= warmup_connection_count
  slots = connection_limit - @connections.size
  count = slots if slots < count

  return unless slots >= count

  idle_manager.log_info "Warming up #{count} connection#{count > 1 ? 's' : ''}"
  synchronize do
    count.times {
      conn = checkout_new_connection
      @available.add conn
    }
  end
end