rails_autoscale_agent 0.7.0 → 0.10.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_autoscale_agent/logger'
4
+
5
+ module RailsAutoscaleAgent
6
+ module WorkerAdapters
7
+ class Que
8
+ include RailsAutoscaleAgent::Logger
9
+ include Singleton
10
+
11
+ attr_writer :queues
12
+
13
+ def queues
14
+ # Track the known queues so we can continue reporting on queues that don't
15
+ # have enqueued jobs at the time of reporting.
16
+ # Assume a "default" queue so we always report *something*, even when nothing
17
+ # is enqueued.
18
+ @queues ||= Set.new(['default'])
19
+ end
20
+
21
+ def enabled?
22
+ if defined?(::Que)
23
+ logger.info "Que enabled (#{::ActiveRecord::Base.default_timezone})"
24
+ true
25
+ end
26
+ end
27
+
28
+ def collect!(store)
29
+ log_msg = String.new
30
+ t = Time.now.utc
31
+ sql = <<~SQL
32
+ SELECT queue, min(run_at)
33
+ FROM que_jobs
34
+ WHERE finished_at IS NULL
35
+ AND expired_at IS NULL
36
+ AND error_count = 0
37
+ GROUP BY 1
38
+ SQL
39
+
40
+ run_at_by_queue = Hash[select_rows(sql)]
41
+
42
+ # Don't collect worker metrics if there are unreasonable number of queues
43
+ if run_at_by_queue.size > 50
44
+ logger.debug "Skipping Que metrics - #{run_at_by_queue.size} queues"
45
+ return
46
+ end
47
+
48
+ self.queues |= run_at_by_queue.keys
49
+
50
+ queues.each do |queue|
51
+ run_at = run_at_by_queue[queue]
52
+ run_at = DateTime.parse(run_at) if run_at.is_a?(String)
53
+ latency_ms = run_at ? ((t - run_at)*1000).ceil : 0
54
+ latency_ms = 0 if latency_ms < 0
55
+
56
+ store.push latency_ms, t, queue
57
+ log_msg << "que.#{queue}=#{latency_ms} "
58
+ end
59
+
60
+ logger.debug log_msg unless log_msg.empty?
61
+ end
62
+
63
+ private
64
+
65
+ def select_rows(sql)
66
+ # This ensures the agent doesn't hold onto a DB connection any longer than necessary
67
+ ActiveRecord::Base.connection_pool.with_connection { |c| c.select_rows(sql) }
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails_autoscale_agent/logger'
4
+
5
+ module RailsAutoscaleAgent
6
+ module WorkerAdapters
7
+ class Resque
8
+ include RailsAutoscaleAgent::Logger
9
+ include Singleton
10
+
11
+ attr_writer :queues
12
+
13
+ def queues
14
+ @queues ||= ['default']
15
+ end
16
+
17
+ def enabled?
18
+ require 'resque'
19
+ logger.info "Resque enabled"
20
+ true
21
+ rescue LoadError
22
+ false
23
+ end
24
+
25
+ def collect!(store)
26
+ log_msg = String.new
27
+ current_queues = ::Resque.queues
28
+
29
+ # Don't collect worker metrics if there are unreasonable number of queues
30
+ if current_queues.size > 50
31
+ logger.debug "Skipping Resque metrics - #{current_queues.size} queues"
32
+ return
33
+ end
34
+
35
+ # Ensure we continue to collect metrics for known queue names, even when nothing is
36
+ # enqueued at the time. Without this, it will appears that the agent is no longer reporting.
37
+ self.queues |= current_queues
38
+
39
+ queues.each do |queue|
40
+ next if queue.nil? || queue.empty?
41
+ depth = ::Resque.size(queue)
42
+ store.push depth, Time.now, queue, :qd
43
+ log_msg << "resque-qd.#{queue}=#{depth} "
44
+ end
45
+
46
+ logger.debug log_msg
47
+ end
48
+ end
49
+ end
50
+ end
@@ -2,28 +2,79 @@
2
2
 
3
3
  require 'rails_autoscale_agent/logger'
4
4
 
5
- module WorkerAdapters
6
- class Sidekiq
7
- include RailsAutoscaleAgent::Logger
8
-
9
- def enabled?
10
- require 'sidekiq/api'
11
- true
12
- rescue LoadError
13
- false
14
- end
5
+ module RailsAutoscaleAgent
6
+ module WorkerAdapters
7
+ class Sidekiq
8
+ include RailsAutoscaleAgent::Logger
9
+ include Singleton
10
+
11
+ attr_writer :queues
12
+
13
+ def enabled?
14
+ require 'sidekiq/api'
15
+
16
+ log_msg = String.new("Sidekiq enabled")
17
+ log_msg << " with long-running job support" if track_long_running_jobs?
18
+ logger.info log_msg
19
+
20
+ true
21
+ rescue LoadError
22
+ false
23
+ end
24
+
25
+ def collect!(store)
26
+ log_msg = String.new
27
+ queues_by_name = ::Sidekiq::Queue.all.each_with_object({}) do |queue, obj|
28
+ obj[queue.name] = queue
29
+ end
30
+
31
+ # Don't collect worker metrics if there are unreasonable number of queues
32
+ if queues_by_name.size > 50
33
+ logger.debug "Skipping Sidekiq metrics - #{queues_by_name.size} queues"
34
+ return
35
+ end
15
36
 
16
- # TODO: specs
17
- def collect!(store)
18
- log_msg = String.new('Sidekiq latency ')
37
+ # Ensure we continue to collect metrics for known queue names, even when nothing is
38
+ # enqueued at the time. Without this, it will appear that the agent is no longer reporting.
39
+ queues.each do |queue_name|
40
+ queues_by_name[queue_name] ||= ::Sidekiq::Queue.new(queue_name)
41
+ end
42
+ self.queues = queues_by_name.keys
19
43
 
20
- ::Sidekiq::Queue.all.each do |queue|
21
- latency_ms = (queue.latency * 1000).ceil
22
- store.push latency_ms, Time.now, queue.name
23
- log_msg << "#{queue.name}=#{latency_ms} "
44
+ if track_long_running_jobs?
45
+ busy_counts = Hash.new { |h,k| h[k] = 0}
46
+ ::Sidekiq::Workers.new.each do |pid, tid, work|
47
+ busy_counts[work.dig('payload', 'queue')] += 1
48
+ end
49
+ end
50
+
51
+ queues_by_name.each do |queue_name, queue|
52
+ latency_ms = (queue.latency * 1000).ceil
53
+ depth = queue.size
54
+
55
+ store.push latency_ms, Time.now, queue.name, :qt
56
+ store.push depth, Time.now, queue.name, :qd
57
+ log_msg << "sidekiq-qt.#{queue.name}=#{latency_ms} sidekiq-qd.#{queue.name}=#{depth} "
58
+
59
+ if track_long_running_jobs?
60
+ busy_count = busy_counts[queue.name]
61
+ store.push busy_count, Time.now, queue.name, :busy
62
+ log_msg << "sidekiq-busy.#{queue.name}=#{busy_count} "
63
+ end
64
+ end
65
+
66
+ logger.debug log_msg
24
67
  end
25
68
 
26
- logger.debug log_msg
69
+ private
70
+
71
+ def queues
72
+ @queues ||= ['default']
73
+ end
74
+
75
+ def track_long_running_jobs?
76
+ Config.instance.track_long_running_jobs
77
+ end
27
78
  end
28
79
  end
29
80
  end
@@ -16,14 +16,5 @@ Gem::Specification.new do |spec|
16
16
  spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
17
17
  spec.require_paths = ["lib"]
18
18
 
19
- spec.add_dependency "activesupport", ">= 3.2"
20
-
21
- spec.add_development_dependency "bundler", "~> 2.0"
22
- spec.add_development_dependency "rake", "~> 10.0"
23
- spec.add_development_dependency "rspec", "~> 3.0"
24
- spec.add_development_dependency "vcr", "~> 3.0"
25
- spec.add_development_dependency "webmock"
26
- spec.add_development_dependency "pry"
27
- spec.add_development_dependency "pry-byebug"
28
- spec.add_development_dependency "sidekiq", "~> 5.0"
19
+ spec.required_ruby_version = '>= 2.5'
29
20
  end
metadata CHANGED
@@ -1,142 +1,16 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails_autoscale_agent
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 0.10.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Adam McCrea
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-12-04 00:00:00.000000000 Z
12
- dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: activesupport
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - ">="
18
- - !ruby/object:Gem::Version
19
- version: '3.2'
20
- type: :runtime
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - ">="
25
- - !ruby/object:Gem::Version
26
- version: '3.2'
27
- - !ruby/object:Gem::Dependency
28
- name: bundler
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - "~>"
32
- - !ruby/object:Gem::Version
33
- version: '2.0'
34
- type: :development
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - "~>"
39
- - !ruby/object:Gem::Version
40
- version: '2.0'
41
- - !ruby/object:Gem::Dependency
42
- name: rake
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - "~>"
46
- - !ruby/object:Gem::Version
47
- version: '10.0'
48
- type: :development
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - "~>"
53
- - !ruby/object:Gem::Version
54
- version: '10.0'
55
- - !ruby/object:Gem::Dependency
56
- name: rspec
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - "~>"
60
- - !ruby/object:Gem::Version
61
- version: '3.0'
62
- type: :development
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - "~>"
67
- - !ruby/object:Gem::Version
68
- version: '3.0'
69
- - !ruby/object:Gem::Dependency
70
- name: vcr
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - "~>"
74
- - !ruby/object:Gem::Version
75
- version: '3.0'
76
- type: :development
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - "~>"
81
- - !ruby/object:Gem::Version
82
- version: '3.0'
83
- - !ruby/object:Gem::Dependency
84
- name: webmock
85
- requirement: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - ">="
88
- - !ruby/object:Gem::Version
89
- version: '0'
90
- type: :development
91
- prerelease: false
92
- version_requirements: !ruby/object:Gem::Requirement
93
- requirements:
94
- - - ">="
95
- - !ruby/object:Gem::Version
96
- version: '0'
97
- - !ruby/object:Gem::Dependency
98
- name: pry
99
- requirement: !ruby/object:Gem::Requirement
100
- requirements:
101
- - - ">="
102
- - !ruby/object:Gem::Version
103
- version: '0'
104
- type: :development
105
- prerelease: false
106
- version_requirements: !ruby/object:Gem::Requirement
107
- requirements:
108
- - - ">="
109
- - !ruby/object:Gem::Version
110
- version: '0'
111
- - !ruby/object:Gem::Dependency
112
- name: pry-byebug
113
- requirement: !ruby/object:Gem::Requirement
114
- requirements:
115
- - - ">="
116
- - !ruby/object:Gem::Version
117
- version: '0'
118
- type: :development
119
- prerelease: false
120
- version_requirements: !ruby/object:Gem::Requirement
121
- requirements:
122
- - - ">="
123
- - !ruby/object:Gem::Version
124
- version: '0'
125
- - !ruby/object:Gem::Dependency
126
- name: sidekiq
127
- requirement: !ruby/object:Gem::Requirement
128
- requirements:
129
- - - "~>"
130
- - !ruby/object:Gem::Version
131
- version: '5.0'
132
- type: :development
133
- prerelease: false
134
- version_requirements: !ruby/object:Gem::Requirement
135
- requirements:
136
- - - "~>"
137
- - !ruby/object:Gem::Version
138
- version: '5.0'
139
- description:
11
+ date: 2021-01-12 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description:
140
14
  email:
141
15
  - adam@adamlogic.com
142
16
  executables: []
@@ -147,6 +21,8 @@ files:
147
21
  - ".rspec"
148
22
  - ".ruby-version"
149
23
  - ".travis.yml"
24
+ - ".vscode/tasks.json"
25
+ - CHANGELOG.md
150
26
  - Gemfile
151
27
  - LICENSE.txt
152
28
  - README.md
@@ -167,6 +43,9 @@ files:
167
43
  - lib/rails_autoscale_agent/store.rb
168
44
  - lib/rails_autoscale_agent/time_rounder.rb
169
45
  - lib/rails_autoscale_agent/version.rb
46
+ - lib/rails_autoscale_agent/worker_adapters/delayed_job.rb
47
+ - lib/rails_autoscale_agent/worker_adapters/que.rb
48
+ - lib/rails_autoscale_agent/worker_adapters/resque.rb
170
49
  - lib/rails_autoscale_agent/worker_adapters/sidekiq.rb
171
50
  - log/.gitkeep
172
51
  - rails_autoscale_agent.gemspec
@@ -174,7 +53,7 @@ homepage: https://github.com/adamlogic/rails_autoscale_agent
174
53
  licenses:
175
54
  - MIT
176
55
  metadata: {}
177
- post_install_message:
56
+ post_install_message:
178
57
  rdoc_options: []
179
58
  require_paths:
180
59
  - lib
@@ -182,15 +61,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
182
61
  requirements:
183
62
  - - ">="
184
63
  - !ruby/object:Gem::Version
185
- version: '0'
64
+ version: '2.5'
186
65
  required_rubygems_version: !ruby/object:Gem::Requirement
187
66
  requirements:
188
67
  - - ">="
189
68
  - !ruby/object:Gem::Version
190
69
  version: '0'
191
70
  requirements: []
192
- rubygems_version: 3.0.3
193
- signing_key:
71
+ rubygems_version: 3.1.4
72
+ signing_key:
194
73
  specification_version: 4
195
74
  summary: This gem works with the Rails Autoscale Heroku add-on to automatically scale
196
75
  your web dynos.