Class: Sidekiq::HerokuAutoscale::HerokuApp
- Inherits:
-
Object
- Object
- Sidekiq::HerokuAutoscale::HerokuApp
- Defined in:
- lib/sidekiq/heroku_autoscale/heroku_app.rb
Instance Attribute Summary collapse
-
#app_name ⇒ Object
readonly
Returns the value of attribute app_name.
-
#history ⇒ Object
readonly
Returns the value of attribute history.
-
#throttle ⇒ Object
readonly
Returns the value of attribute throttle.
Instance Method Summary collapse
- #history_stats(now = Time.now.utc) ⇒ Object
-
#initialize(config) ⇒ HerokuApp
constructor
Builds process managers based on configuration (presumably loaded from YAML).
-
#live? ⇒ Boolean
checks if there’s a live Heroku client setup.
-
#ping! ⇒ Object
pings all processes in the application useful for requesting live updates.
- #process_by_name(process_name) ⇒ Object
- #process_for_queue(queue_name) ⇒ Object
- #process_names ⇒ Object
- #processes ⇒ Object
- #queue_names ⇒ Object
- #stats ⇒ Object
Constructor Details
#initialize(config) ⇒ HerokuApp
Builds process managers based on configuration (presumably loaded from YAML)
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
# File 'lib/sidekiq/heroku_autoscale/heroku_app.rb', line 10 def initialize(config) config = JSON.parse(JSON.generate(config), symbolize_names: true) api_token = config[:api_token] || ENV['SIDEKIQ_HEROKU_AUTOSCALE_API_TOKEN'] @app_name = config[:app_name] || ENV['SIDEKIQ_HEROKU_AUTOSCALE_APP'] @throttle = config[:throttle] || 10 @history = config[:history] || 60 * 60 # 1 hour @client = api_token ? PlatformAPI.connect_oauth(api_token) : nil @processes_by_name = {} @processes_by_queue = {} config[:processes].each_pair do |name, opts| process = Process.new( app_name: @app_name, name: name, client: @client, throttle: @throttle, history: @history, **opts.slice(:system, :scale, :quiet_buffer) ) @processes_by_name[name.to_s] = process process.queue_system.watch_queues.each do |queue_name| # a queue may only be managed by a single heroku process type (to avoid scaling conflicts) # thus, raise an error over duplicate queue names or when "*" isn't exclusive if @processes_by_queue.key?(queue_name) || @processes_by_queue.key?('*') || (queue_name == '*' && @processes_by_queue.keys.any?) raise ArgumentError, 'watched queues must be exclusive to a single Heroku process type' end @processes_by_queue[queue_name] = process end end end |
Instance Attribute Details
#app_name ⇒ Object (readonly)
Returns the value of attribute app_name.
7 8 9 |
# File 'lib/sidekiq/heroku_autoscale/heroku_app.rb', line 7 def app_name @app_name end |
#history ⇒ Object (readonly)
Returns the value of attribute history.
7 8 9 |
# File 'lib/sidekiq/heroku_autoscale/heroku_app.rb', line 7 def history @history end |
#throttle ⇒ Object (readonly)
Returns the value of attribute throttle.
7 8 9 |
# File 'lib/sidekiq/heroku_autoscale/heroku_app.rb', line 7 def throttle @throttle end |
Instance Method Details
#history_stats(now = Time.now.utc) ⇒ Object
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 |
# File 'lib/sidekiq/heroku_autoscale/heroku_app.rb', line 87 def history_stats(now=Time.now.utc) # calculate a series time to anchor graph ticks on # the series snaps to thresholds of N (throttle duration) series_time = (now.to_f / @throttle).floor * @throttle num_ticks = (@history / @throttle).floor first_tick = series_time - @throttle * num_ticks # all ticks is a hash of timestamp keys to plot all_ticks = Array.new(num_ticks) .each_with_index.map { |v, i| (first_tick + @throttle * i).to_s } .each_with_object({}) { |tick, memo| memo[tick] = nil } # get current and previous history collections for each process # history pages snap to thresholds of M (history duration) current_page = (now.to_f / @history).floor * @history previous_page = current_page - @history history_pages = ::Sidekiq.redis do |c| c.pipelined do processes.each do |process| c.hgetall("#{ process.cache_key }:#{ previous_page }") c.hgetall("#{ process.cache_key }:#{ current_page }") end end end history_by_process = {} history_pages.each_slice(2).each_with_index do |(a, b), i| process = processes[i] # flatten all history pages into a single collection ticks = all_ticks .merge(a.merge!(b)) .map { |k, v| [k.to_i, v ? v.to_i : nil] } .sort_by { |tick| tick[0] } # separate the older stats from the current history timeframe past_ticks, present_ticks = ticks.partition { |tick| tick[0] < first_tick } # select a running value starting point # run from the end of past history, or beginning of present history, or current dynos value = past_ticks.last || present_ticks.detect { |tick| !!tick[1] } value = value ? value[1] : process.dynos # assign a running value across all ticks present_ticks.each do |tick| tick[1] ||= value value = tick[1] end history_by_process[process.name] = present_ticks end history_by_process end |
#live? ⇒ Boolean
checks if there’s a live Heroku client setup
45 46 47 |
# File 'lib/sidekiq/heroku_autoscale/heroku_app.rb', line 45 def live? !!@client end |
#ping! ⇒ Object
pings all processes in the application useful for requesting live updates
51 52 53 |
# File 'lib/sidekiq/heroku_autoscale/heroku_app.rb', line 51 def ping! processes.each(&:ping!) end |
#process_by_name(process_name) ⇒ Object
67 68 69 |
# File 'lib/sidekiq/heroku_autoscale/heroku_app.rb', line 67 def process_by_name(process_name) @processes_by_name[process_name] end |
#process_for_queue(queue_name) ⇒ Object
71 72 73 |
# File 'lib/sidekiq/heroku_autoscale/heroku_app.rb', line 71 def process_for_queue(queue_name) @processes_by_queue[queue_name] || @processes_by_queue['*'] end |
#process_names ⇒ Object
59 60 61 |
# File 'lib/sidekiq/heroku_autoscale/heroku_app.rb', line 59 def process_names @process_names ||= @processes_by_name.keys end |
#processes ⇒ Object
55 56 57 |
# File 'lib/sidekiq/heroku_autoscale/heroku_app.rb', line 55 def processes @processes ||= @processes_by_name.values end |
#queue_names ⇒ Object
63 64 65 |
# File 'lib/sidekiq/heroku_autoscale/heroku_app.rb', line 63 def queue_names @queue_names ||= @processes_by_queue.keys end |
#stats ⇒ Object
75 76 77 78 79 80 81 82 83 84 85 |
# File 'lib/sidekiq/heroku_autoscale/heroku_app.rb', line 75 def stats histories = history_stats processes.each_with_object({}) do |process, memo| memo[process.name] = { dynos: process.dynos, status: process.status, updated: process.updated_at.to_s, history: histories[process.name], } end end |