sidekiq-cloudwatchmetrics 1.0.1

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,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 0d12e8127fc1e085dfafd8812c3fca0ca8f60d84a18d0c1075df44f3d73dfa7e
4
+ data.tar.gz: d122fa6c24b657283c383e00a64be1d6d61ec1f22f6eabb1eb42d14b590992b9
5
+ SHA512:
6
+ metadata.gz: 86028f3e083b24983f2bf59a850e996c76bd6a0f09c200bcecb386ab914dd5fc48c70ba1fb2ac44edee0db2c22b190eeac79f46f6b609195a067ee7665841218
7
+ data.tar.gz: 9a0119a1004c93d68837980ed58103fe293026e89e37ef1d3d39312bdccf038152c73812f0189c1fbb82a713514804ab7e711374086bc2082c7ac6fa96d5bc0f
@@ -0,0 +1,2 @@
1
+ SSf�`Q�ҹ4����Uz<)� �M�B쭴��mˬf�*�S�$/
2
+ ��@���4�[�:k ����>�,T� n�L�NJ)%ф�t�������a�������C��ҙ\`�x�*�G���uV+�)XdH�ν��+�G �*ܖ����v5A���3׼+�a¤>,���N���]��,O�R��r��c�^�kVz ���:ri� ꟰Y9H�?�8"z�%�]S �-f%�tJ����\c�e�E[�G��R
Binary file
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2018 Samuel Cochran
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,52 @@
1
+ # Sidekiq CloudWatch Metrics
2
+
3
+ Runs a thread inside your Sidekiq processes to report metrics to CloudWatch
4
+ useful for autoscaling and keeping an eye on your queues.
5
+
6
+ Optimised for Sidekiq Enterprise with leader election, but works everywhere!
7
+
8
+ ## Installation
9
+
10
+ Add this gem to your application’s Gemfile near sidekiq and then run `bundle install`:
11
+
12
+ ```ruby
13
+ gem "sidekiq"
14
+ gem "sidekiq-cloudwatchmetrics"
15
+ ```
16
+
17
+ ## Usage
18
+
19
+ Add near your Sidekiq configuration, like in `config/initializers/sidekiq.rb` in Rails:
20
+
21
+ ```ruby
22
+ require "sidekiq"
23
+ require "sidekiq/cloudwatchmetrics"
24
+
25
+ Sidekiq::CloudWatchMetrics.enable!
26
+ ```
27
+
28
+ By default this assumes you're running on an EC2 instance with an instance role
29
+ that can publish CloudWatch metrics, or that you've supplied AWS credentials
30
+ through environment variables that aws-sdk expects. You can also explicitly
31
+ supply an [aws-sdk CloudWatch Client instance][cwclient]:
32
+
33
+ ```ruby
34
+ Sidekiq::CloudWatchMetrics.enable!(client: AWS::CloudWatch::Client.new)
35
+ ```
36
+
37
+ [cwclient]: https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/CloudWatch/Client.html
38
+
39
+ ## Development
40
+
41
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
42
+
43
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
44
+
45
+ ## Contributing
46
+
47
+ Bug reports and pull requests are welcome on GitHub at https://github.com/sj26/sidekiq-cloudwatchmetrics.
48
+
49
+ ## License
50
+
51
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
52
+
@@ -0,0 +1,206 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "sidekiq"
4
+ require "sidekiq/api"
5
+ require "sidekiq/util"
6
+
7
+ require "aws-sdk-cloudwatch"
8
+
9
+ module Sidekiq::CloudWatchMetrics
10
+ def self.enable!(**kwargs)
11
+ Sidekiq.configure_server do |config|
12
+ publisher = Publisher.new(**kwargs)
13
+
14
+ if Sidekiq.options[:lifecycle_events].has_key?(:leader)
15
+ # Only publish metrics on the leader if we have a leader (sidekiq-ent)
16
+ config.on(:leader) do
17
+ publisher.start
18
+ end
19
+ else
20
+ # Otherwise pubishing from every node doesn't hurt, it's just wasteful
21
+ config.on(:startup) do
22
+ publisher.start
23
+ end
24
+ end
25
+
26
+ config.on(:quiet) do
27
+ publisher.quiet if publisher.running?
28
+ end
29
+
30
+ config.on(:shutdown) do
31
+ publisher.stop if publisher.running?
32
+ end
33
+ end
34
+ end
35
+
36
+ class Publisher
37
+ include Sidekiq::Util
38
+
39
+ INTERVAL = 60 # seconds
40
+
41
+ def initialize(client: Aws::CloudWatch::Client.new)
42
+ @client = client
43
+ end
44
+
45
+ def start
46
+ logger.info { "Starting Sidekiq CloudWatch Metrics Publisher" }
47
+
48
+ @done = false
49
+ @thread = safe_thread("cloudwatch metrics publisher", &method(:run))
50
+ end
51
+
52
+ def running?
53
+ !@thread.nil? && @thread.alive?
54
+ end
55
+
56
+ def run
57
+ logger.info { "Started Sidekiq CloudWatch Metrics Publisher" }
58
+
59
+ # Publish stats every INTERVAL seconds, sleeping as required between runs
60
+ now = Time.now.to_f
61
+ tick = now
62
+ until @stop
63
+ logger.info { "Publishing Sidekiq CloudWatch Metrics" }
64
+ publish
65
+
66
+ now = Time.now.to_f
67
+ tick = [tick + INTERVAL, now].max
68
+ sleep(tick - now) if tick > now
69
+ end
70
+
71
+ logger.info { "Stopped Sidekiq CloudWatch Metrics Publisher" }
72
+ end
73
+
74
+ def publish
75
+ now = Time.now
76
+ stats = Sidekiq::Stats.new
77
+ processes = Sidekiq::ProcessSet.new.to_enum(:each).to_a
78
+ utilization = calculate_utilization(processes)
79
+ capacity = calculate_capacity(processes)
80
+ queues = stats.queues
81
+
82
+ metrics = [
83
+ {
84
+ metric_name: "ProcessedJobs",
85
+ timestamp: now,
86
+ value: stats.processed,
87
+ unit: "Count",
88
+ },
89
+ {
90
+ metric_name: "FailedJobs",
91
+ timestamp: now,
92
+ value: stats.failed,
93
+ unit: "Count",
94
+ },
95
+ {
96
+ metric_name: "EnqueuedJobs",
97
+ timestamp: now,
98
+ value: stats.enqueued,
99
+ unit: "Count",
100
+ },
101
+ {
102
+ metric_name: "ScheduledJobs",
103
+ timestamp: now,
104
+ value: stats.scheduled_size,
105
+ unit: "Count",
106
+ },
107
+ {
108
+ metric_name: "RetryJobs",
109
+ timestamp: now,
110
+ value: stats.retry_size,
111
+ unit: "Count",
112
+ },
113
+ {
114
+ metric_name: "DeadJobs",
115
+ timestamp: now,
116
+ value: stats.dead_size,
117
+ unit: "Count",
118
+ },
119
+ {
120
+ metric_name: "Workers",
121
+ timestamp: now,
122
+ value: stats.workers_size,
123
+ unit: "Count",
124
+ },
125
+ {
126
+ metric_name: "Processes",
127
+ timestamp: now,
128
+ value: stats.processes_size,
129
+ unit: "Count",
130
+ },
131
+ {
132
+ metric_name: "Capacity",
133
+ timestamp: now,
134
+ value: capacity,
135
+ unit: "Count",
136
+ },
137
+ {
138
+ metric_name: "Utilization",
139
+ timestamp: now,
140
+ value: utilization * 100.0,
141
+ unit: "Percent",
142
+ },
143
+ {
144
+ metric_name: "DefaultQueueLatency",
145
+ timestamp: now,
146
+ value: stats.default_queue_latency,
147
+ unit: "Seconds",
148
+ },
149
+ ]
150
+
151
+ queues.map do |(queue_name, queue_size)|
152
+ metrics << {
153
+ metric_name: "QueueSize",
154
+ dimensions: [{name: "QueueName", value: queue_name}],
155
+ timestamp: now,
156
+ value: queue_size,
157
+ unit: "Count",
158
+ }
159
+
160
+ queue_latency = Sidekiq::Queue.new(queue_name).latency
161
+
162
+ metrics << {
163
+ metric_name: "QueueLatency",
164
+ dimensions: [{name: "QueueName", value: queue_name}],
165
+ timestamp: now,
166
+ value: queue_latency,
167
+ unit: "Seconds",
168
+ }
169
+ end
170
+
171
+ # We can only put 20 metrics at a time
172
+ metrics.each_slice(20) do |some_metrics|
173
+ @client.put_metric_data(
174
+ namespace: "Sidekiq",
175
+ metric_data: some_metrics,
176
+ )
177
+ end
178
+ end
179
+
180
+ # Returns the total number of workers across all processes
181
+ private def calculate_capacity(processes)
182
+ processes.map do |process|
183
+ process["concurrency"]
184
+ end.sum
185
+ end
186
+
187
+ # Returns busy / concurrency averaged across processes (for scaling)
188
+ private def calculate_utilization(processes)
189
+ processes.map do |process|
190
+ process["busy"] / process["concurrency"].to_f
191
+ end.sum / processes.size.to_f
192
+ end
193
+
194
+ def quiet
195
+ logger.info { "Quieting Sidekiq CloudWatch Metrics Publisher" }
196
+ @stop = true
197
+ end
198
+
199
+ def stop
200
+ logger.info { "Stopping Sidekiq CloudWatch Metrics Publisher" }
201
+ @stop = true
202
+ @thread.wakeup
203
+ @thread.join
204
+ end
205
+ end
206
+ end
metadata ADDED
@@ -0,0 +1,154 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sidekiq-cloudwatchmetrics
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Samuel Cochran
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain:
11
+ - |
12
+ -----BEGIN CERTIFICATE-----
13
+ MIIDKDCCAhCgAwIBAgIBBjANBgkqhkiG9w0BAQsFADA6MQ0wCwYDVQQDDARzajI2
14
+ MRQwEgYKCZImiZPyLGQBGRYEc2oyNjETMBEGCgmSJomT8ixkARkWA2NvbTAeFw0x
15
+ ODA4MTYwNTE4NDBaFw0xOTA4MTYwNTE4NDBaMDoxDTALBgNVBAMMBHNqMjYxFDAS
16
+ BgoJkiaJk/IsZAEZFgRzajI2MRMwEQYKCZImiZPyLGQBGRYDY29tMIIBIjANBgkq
17
+ hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsr60Eo/ttCk8GMTMFiPr3GoYMIMFvLak
18
+ xSmTk9YGCB6UiEePB4THSSA5w6IPyeaCF/nWkDp3/BAam0eZMWG1IzYQB23TqIM0
19
+ 1xzcNRvFsn0aQoQ00k+sj+G83j3T5OOV5OZIlu8xAChMkQmiPd1NXc6uFv+Iacz7
20
+ kj+CMsI9YUFdNoU09QY0b+u+Rb6wDYdpyvN60YC30h0h1MeYbvYZJx/iZK4XY5zu
21
+ 4O/FL2ChjL2CPCpLZW55ShYyrzphWJwLOJe+FJ/ZBl6YXwrzQM9HKnt4titSNvyU
22
+ KzE3L63A3PZvExzLrN9u09kuWLLJfXB2sGOlw3n9t72rJiuBr3/OQQIDAQABozkw
23
+ NzAJBgNVHRMEAjAAMAsGA1UdDwQEAwIEsDAdBgNVHQ4EFgQU99dfRjEKFyczTeIz
24
+ m3ZsDWrNC80wDQYJKoZIhvcNAQELBQADggEBAEwUQFizoyvm/1/iX8i/+oK6hr5m
25
+ wd7ZEzIV32JRyaqkPFeWjBylRXZyoXsE2u1H9ofIw8b/5/M+uMIfR8jlJSuulGB7
26
+ rs3ixWpkwRW8Knz2A5zufM3uPypwDYbEUbTdhzqY9hCzCz4moHu2E5f5bz7zrp+g
27
+ kpFjMoo851LRGr5vEQMZ/U+Paq8ROLzAiOa72mNxIFzvnGcSDyBVixdewi7HoZWD
28
+ ccrr0sGoLnfK6DappOwH1I5uPvQohOATNmmU0MSSWOeiggLlEWmUYE7CvzoMc8R6
29
+ DlumKi5y9wE+XnxtyLbe6GlT3AkVGnhwPdwq2QBFLEWkTVogdCYomBCKfjY=
30
+ -----END CERTIFICATE-----
31
+ date: 2018-08-16 00:00:00.000000000 Z
32
+ dependencies:
33
+ - !ruby/object:Gem::Dependency
34
+ name: sidekiq
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '5.0'
40
+ type: :runtime
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '5.0'
47
+ - !ruby/object:Gem::Dependency
48
+ name: aws-sdk-cloudwatch
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '1.6'
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '1.6'
61
+ - !ruby/object:Gem::Dependency
62
+ name: bundler
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '1.16'
68
+ type: :development
69
+ prerelease: false
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '1.16'
75
+ - !ruby/object:Gem::Dependency
76
+ name: rake
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: '10.0'
82
+ type: :development
83
+ prerelease: false
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - "~>"
87
+ - !ruby/object:Gem::Version
88
+ version: '10.0'
89
+ - !ruby/object:Gem::Dependency
90
+ name: rspec
91
+ requirement: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - "~>"
94
+ - !ruby/object:Gem::Version
95
+ version: '3.7'
96
+ type: :development
97
+ prerelease: false
98
+ version_requirements: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - "~>"
101
+ - !ruby/object:Gem::Version
102
+ version: '3.7'
103
+ - !ruby/object:Gem::Dependency
104
+ name: timecop
105
+ requirement: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - "~>"
108
+ - !ruby/object:Gem::Version
109
+ version: '0.9'
110
+ type: :development
111
+ prerelease: false
112
+ version_requirements: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - "~>"
115
+ - !ruby/object:Gem::Version
116
+ version: '0.9'
117
+ description: |
118
+ Runs a thread inside your Sidekiq processes to report metrics to CloudWatch
119
+ useful for autoscaling and keeping an eye on your queues.
120
+
121
+ Optimised for Sidekiq Enterprise with leader election, but works everywhere!
122
+ email: sj26@sj26.com
123
+ executables: []
124
+ extensions: []
125
+ extra_rdoc_files: []
126
+ files:
127
+ - LICENSE
128
+ - README.md
129
+ - lib/sidekiq/cloudwatchmetrics.rb
130
+ homepage: https://github.com/sj26/sidekiq-cloudwatchmetrics
131
+ licenses:
132
+ - MIT
133
+ metadata: {}
134
+ post_install_message:
135
+ rdoc_options: []
136
+ require_paths:
137
+ - lib
138
+ required_ruby_version: !ruby/object:Gem::Requirement
139
+ requirements:
140
+ - - "~>"
141
+ - !ruby/object:Gem::Version
142
+ version: '2.4'
143
+ required_rubygems_version: !ruby/object:Gem::Requirement
144
+ requirements:
145
+ - - ">="
146
+ - !ruby/object:Gem::Version
147
+ version: '0'
148
+ requirements: []
149
+ rubyforge_project:
150
+ rubygems_version: 2.7.7
151
+ signing_key:
152
+ specification_version: 4
153
+ summary: Publish Sidekiq metrics to AWS CloudWatch
154
+ test_files: []
@@ -0,0 +1,2 @@
1
+
2
+ ɴXBLX(D�B%ș��œٯ<0�v���xj[�@ʯo�J�W�醾~xn3"����=x��,�蔼�LF�>�b`�X��C�hH&