sidekiq_status_monitor 1.0.0
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.
- checksums.yaml +7 -0
- data/README.md +233 -0
- data/lib/sidekiq_status_monitor/config.rb +39 -0
- data/lib/sidekiq_status_monitor/helpers.rb +27 -0
- data/lib/sidekiq_status_monitor/redis/base.rb +35 -0
- data/lib/sidekiq_status_monitor/redis/redis_client_gem.rb +52 -0
- data/lib/sidekiq_status_monitor/redis/redis_gem.rb +45 -0
- data/lib/sidekiq_status_monitor/redis.rb +15 -0
- data/lib/sidekiq_status_monitor/server.rb +44 -0
- data/lib/sidekiq_status_monitor/version.rb +3 -0
- data/lib/sidekiq_status_monitor.rb +144 -0
- metadata +230 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: cff542b7575a5a9d3056126393cda3f7e8b8488f237fcc620bb8d4786f9b45b6
|
4
|
+
data.tar.gz: 1117ed0ee145457b1ab9931a9610702532612e12142aa9881fc25cafc3649287
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ab1cd10cfa90f87275e1b13794c57369d99394d3fe3bca58163c98af5c92c2315b0d12ac4e20eff2a406a20e27be7457e04813232fcf2dc9d6ecc8dd38b3bccd
|
7
|
+
data.tar.gz: 3a1a817db8c0142ecb061fe442501d72e0b90e870852c72cf933070b1d5aea5ed1c904c999d4f57e0a77497b95cc6418b276566fdef002316661079b84d8c177
|
data/README.md
ADDED
@@ -0,0 +1,233 @@
|
|
1
|
+
# SidekiqStatusMonitor
|
2
|
+
|
3
|
+
[](https://rubygems.org/gems/sidekiq_status_monitor)
|
4
|
+
[](https://rubygems.org/gems/https://rubygems.org/gems/sidekiq_status_monitor)
|
5
|
+
|
6
|
+
---
|
7
|
+
|
8
|
+
SidekiqStatusMonitor offers a solution to add liveness probe for a Sidekiq instance deployed in Kubernetes.
|
9
|
+
This library can be used to check sidekiq health outside kubernetes.
|
10
|
+
|
11
|
+
**How?**
|
12
|
+
|
13
|
+
A http server is started and on each requests validates that a liveness key is stored in Redis. If it is there means is working.
|
14
|
+
|
15
|
+
A Sidekiq worker is the responsible to storing this key. If Sidekiq stops processing workers
|
16
|
+
this key gets expired by Redis an consequently the http server will return a 500 error.
|
17
|
+
|
18
|
+
This worker is responsible to requeue itself for the next liveness probe.
|
19
|
+
|
20
|
+
Each instance in kubernetes will be checked based on `ENV` variable `HOSTNAME` (kubernetes sets this for each replica/pod).
|
21
|
+
|
22
|
+
On initialization SidekiqStatusMonitor will asign to Sidekiq::Worker a queue with the current host and add this queue to the current instance queues to process.
|
23
|
+
|
24
|
+
example:
|
25
|
+
|
26
|
+
```
|
27
|
+
hostname: foo
|
28
|
+
Worker queue: sidekiq_status_monitor-foo
|
29
|
+
instance queues:
|
30
|
+
- sidekiq_status_monitor-foo
|
31
|
+
*- your queues
|
32
|
+
|
33
|
+
hostname: bar
|
34
|
+
Worker queue: sidekiq_status_monitor-bar
|
35
|
+
instance queues:
|
36
|
+
- sidekiq_status_monitor-bar
|
37
|
+
*- your queues
|
38
|
+
```
|
39
|
+
|
40
|
+
## Installation
|
41
|
+
|
42
|
+
Add this line to your application's Gemfile:
|
43
|
+
|
44
|
+
```ruby
|
45
|
+
gem 'sidekiq_status_monitor'
|
46
|
+
```
|
47
|
+
|
48
|
+
And then execute:
|
49
|
+
|
50
|
+
$ bundle
|
51
|
+
|
52
|
+
Or install it yourself as:
|
53
|
+
|
54
|
+
$ gem install sidekiq_status_monitor
|
55
|
+
|
56
|
+
## Usage
|
57
|
+
|
58
|
+
SidekiqStatusMonitor will start when running `sidekiq` command.
|
59
|
+
|
60
|
+
Run `Sidekiq`:
|
61
|
+
|
62
|
+
```bash
|
63
|
+
bundle exec sidekiq
|
64
|
+
```
|
65
|
+
|
66
|
+
Bash example:
|
67
|
+
|
68
|
+
```bash
|
69
|
+
curl -v localhost:7433
|
70
|
+
```
|
71
|
+
|
72
|
+
Ruby example:
|
73
|
+
|
74
|
+
```ruby
|
75
|
+
uri = URI.parse("http://localhost:7433")
|
76
|
+
Net::HTTP.get_response(uri).body
|
77
|
+
```
|
78
|
+
|
79
|
+
**how to disable?**
|
80
|
+
You can disabled by setting `ENV` variable `DISABLE_SIDEKIQ_STATUS`
|
81
|
+
example:
|
82
|
+
|
83
|
+
```bash
|
84
|
+
DISABLE_SIDEKIQ_STATUS=true bundle exec sidekiq
|
85
|
+
```
|
86
|
+
|
87
|
+
### Kubernetes setup
|
88
|
+
|
89
|
+
Set `livenessProbe` and `readinessProbe` in your Kubernetes deployment
|
90
|
+
|
91
|
+
example with recommended setup:
|
92
|
+
|
93
|
+
#### Sidekiq < 6
|
94
|
+
|
95
|
+
```yaml
|
96
|
+
spec:
|
97
|
+
containers:
|
98
|
+
- name: my_app
|
99
|
+
image: my_app:latest
|
100
|
+
env:
|
101
|
+
- name: RAILS_ENV
|
102
|
+
value: production
|
103
|
+
command:
|
104
|
+
- bundle
|
105
|
+
- exec
|
106
|
+
- sidekiq
|
107
|
+
ports:
|
108
|
+
- containerPort: 7433
|
109
|
+
livenessProbe:
|
110
|
+
httpGet:
|
111
|
+
path: /
|
112
|
+
port: 7433
|
113
|
+
initialDelaySeconds: 80 # app specific. Time your sidekiq takes to start processing.
|
114
|
+
timeoutSeconds: 5 # can be much less
|
115
|
+
readinessProbe:
|
116
|
+
httpGet:
|
117
|
+
path: /
|
118
|
+
port: 7433
|
119
|
+
initialDelaySeconds: 80 # app specific
|
120
|
+
timeoutSeconds: 5 # can be much less
|
121
|
+
lifecycle:
|
122
|
+
preStop:
|
123
|
+
exec:
|
124
|
+
# SIGTERM triggers a quick exit; gracefully terminate instead
|
125
|
+
command: ['bundle', 'exec', 'sidekiqctl', 'quiet']
|
126
|
+
terminationGracePeriodSeconds: 60 # put your longest Job time here plus security time.
|
127
|
+
```
|
128
|
+
|
129
|
+
#### Sidekiq >= 6
|
130
|
+
|
131
|
+
Create file:
|
132
|
+
|
133
|
+
_kube/sidekiq_quiet_
|
134
|
+
|
135
|
+
```bash
|
136
|
+
#!/bin/bash
|
137
|
+
|
138
|
+
# Find Pid
|
139
|
+
SIDEKIQ_PID=$(ps aux | grep sidekiq | grep busy | awk '{ print $2 }')
|
140
|
+
# Send TSTP signal
|
141
|
+
kill -SIGTSTP $SIDEKIQ_PID
|
142
|
+
```
|
143
|
+
|
144
|
+
Make it executable:
|
145
|
+
|
146
|
+
```
|
147
|
+
$ chmod +x kube/sidekiq_quiet
|
148
|
+
```
|
149
|
+
|
150
|
+
Execute it in your deployment preStop:
|
151
|
+
|
152
|
+
```yaml
|
153
|
+
spec:
|
154
|
+
containers:
|
155
|
+
- name: my_app
|
156
|
+
image: my_app:latest
|
157
|
+
env:
|
158
|
+
- name: RAILS_ENV
|
159
|
+
value: production
|
160
|
+
command:
|
161
|
+
- bundle
|
162
|
+
- exec
|
163
|
+
- sidekiq
|
164
|
+
ports:
|
165
|
+
- containerPort: 7433
|
166
|
+
livenessProbe:
|
167
|
+
httpGet:
|
168
|
+
path: /
|
169
|
+
port: 7433
|
170
|
+
initialDelaySeconds: 80 # app specific. Time your sidekiq takes to start processing.
|
171
|
+
timeoutSeconds: 5 # can be much less
|
172
|
+
readinessProbe:
|
173
|
+
httpGet:
|
174
|
+
path: /
|
175
|
+
port: 7433
|
176
|
+
initialDelaySeconds: 80 # app specific
|
177
|
+
timeoutSeconds: 5 # can be much less
|
178
|
+
lifecycle:
|
179
|
+
preStop:
|
180
|
+
exec:
|
181
|
+
# SIGTERM triggers a quick exit; gracefully terminate instead
|
182
|
+
command: ['kube/sidekiq_quiet']
|
183
|
+
terminationGracePeriodSeconds: 60 # put your longest Job time here plus security time.
|
184
|
+
```
|
185
|
+
|
186
|
+
## Options
|
187
|
+
|
188
|
+
```ruby
|
189
|
+
SidekiqStatusMonitor.setup do |config|
|
190
|
+
# ==> Server host
|
191
|
+
# Host to bind the server.
|
192
|
+
# Can also be set with the environment variable sidekiq_status_HOST.
|
193
|
+
# default: 0.0.0.0
|
194
|
+
#
|
195
|
+
# config.host = 0.0.0.0
|
196
|
+
|
197
|
+
# ==> Server port
|
198
|
+
# Port to bind the server.
|
199
|
+
# Can also be set with the environment variable sidekiq_status_PORT.
|
200
|
+
# default: 7433
|
201
|
+
#
|
202
|
+
# config.port = 7433
|
203
|
+
|
204
|
+
# ==> Shutdown callback
|
205
|
+
# When sidekiq process is shutting down, you can perform some action, like cleaning up created queue
|
206
|
+
# default: proc {}
|
207
|
+
#
|
208
|
+
# config.shutdown_callback = proc do
|
209
|
+
# Sidekiq::Queue.all.find { |q| q.name == "#{config.queue_prefix}-#{SidekiqStatusMonitor.hostname}" }&.clear
|
210
|
+
# end
|
211
|
+
|
212
|
+
# ==> Rack server
|
213
|
+
# Web server used to serve an HTTP response, e.g. 'webrick', 'puma', 'thin', etc.
|
214
|
+
# Can also be set with the environment variable sidekiq_status_SERVER.
|
215
|
+
# default: 'webrick'
|
216
|
+
#
|
217
|
+
# config.server = 'puma'
|
218
|
+
end
|
219
|
+
```
|
220
|
+
|
221
|
+
## Development
|
222
|
+
|
223
|
+
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.
|
224
|
+
|
225
|
+
To install this gem onto your local machine, run `bundle exec rake install`.
|
226
|
+
|
227
|
+
## Contributing
|
228
|
+
|
229
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/arturictus/sidekiq_status_monitor. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
|
230
|
+
|
231
|
+
## License
|
232
|
+
|
233
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SidekiqStatusMonitor
|
4
|
+
class Config
|
5
|
+
include Singleton
|
6
|
+
|
7
|
+
attr_accessor :host,
|
8
|
+
:port,
|
9
|
+
:path,
|
10
|
+
:server,
|
11
|
+
:logger,
|
12
|
+
:shutdown_callback,
|
13
|
+
:workers_size_threshold,
|
14
|
+
:process_set_size_threshold,
|
15
|
+
:queues_size_threshold,
|
16
|
+
:queue_latency_threshold,
|
17
|
+
:queue_size_threshold
|
18
|
+
|
19
|
+
def initialize
|
20
|
+
set_defaults
|
21
|
+
end
|
22
|
+
|
23
|
+
def set_defaults
|
24
|
+
@logger = Sidekiq.logger
|
25
|
+
|
26
|
+
@host = ENV.fetch("SIDEKIQ_STATUS_HOST", "0.0.0.0")
|
27
|
+
@port = ENV.fetch("SIDEKIQ_STATUS_PORT", 7433)
|
28
|
+
@server = ENV.fetch("SIDEKIQ_STATUS_SERVER", "webrick")
|
29
|
+
|
30
|
+
@shutdown_callback = proc {}
|
31
|
+
|
32
|
+
@workers_size_threshold = 0
|
33
|
+
@process_set_size_threshold = 1
|
34
|
+
@queues_size_threshold = 1
|
35
|
+
@queue_latency_threshold = 30 * 60
|
36
|
+
@queue_size_threshold = 1_000_000
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SidekiqStatusMonitor
|
4
|
+
module Helpers
|
5
|
+
class << self
|
6
|
+
def sidekiq_7
|
7
|
+
current_sidekiq_version >= Gem::Version.new("7")
|
8
|
+
end
|
9
|
+
|
10
|
+
def sidekiq_6
|
11
|
+
current_sidekiq_version >= Gem::Version.new("6") &&
|
12
|
+
current_sidekiq_version < Gem::Version.new("7")
|
13
|
+
end
|
14
|
+
|
15
|
+
def sidekiq_5
|
16
|
+
current_sidekiq_version >= Gem::Version.new("5") &&
|
17
|
+
current_sidekiq_version < Gem::Version.new("6")
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def current_sidekiq_version
|
23
|
+
Gem.loaded_specs["sidekiq"].version
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SidekiqStatusMonitor
|
4
|
+
module Redis
|
5
|
+
class Base
|
6
|
+
def set(...)
|
7
|
+
raise(NotImplementedError)
|
8
|
+
end
|
9
|
+
|
10
|
+
def zadd(set_key, ex, key)
|
11
|
+
raise(NotImplementedError)
|
12
|
+
end
|
13
|
+
|
14
|
+
def zrange(set_key, start, stop)
|
15
|
+
raise(NotImplementedError)
|
16
|
+
end
|
17
|
+
|
18
|
+
def zrangebyscore(set_key, min, max)
|
19
|
+
raise(NotImplementedError)
|
20
|
+
end
|
21
|
+
|
22
|
+
def zrem(set_key, key)
|
23
|
+
raise(NotImplementedError)
|
24
|
+
end
|
25
|
+
|
26
|
+
def delete(key)
|
27
|
+
raise(NotImplementedError)
|
28
|
+
end
|
29
|
+
|
30
|
+
def ttl(...)
|
31
|
+
redis { |r| r.ttl(...) }
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "base"
|
4
|
+
|
5
|
+
module SidekiqStatusMonitor
|
6
|
+
module Redis
|
7
|
+
# Wrapper for `redis-client` gem used by `sidekiq` > 7
|
8
|
+
# https://github.com/redis-rb/redis-client
|
9
|
+
class RedisClientGem < Base
|
10
|
+
def initialize
|
11
|
+
super
|
12
|
+
|
13
|
+
@capsule = Sidekiq.default_configuration.capsules[CAPSULE_NAME]
|
14
|
+
end
|
15
|
+
|
16
|
+
def set(key, time:, ex:)
|
17
|
+
redis { |r| r.call("SET", key, time, ex: ex) }
|
18
|
+
end
|
19
|
+
|
20
|
+
def get(key)
|
21
|
+
redis { |r| r.call("GET", key) }
|
22
|
+
end
|
23
|
+
|
24
|
+
def zadd(set_key, ex, key)
|
25
|
+
redis { |r| r.call("ZADD", set_key, ex, key) }
|
26
|
+
end
|
27
|
+
|
28
|
+
def zrange(set_key, start, stop)
|
29
|
+
redis { |r| r.call("ZRANGE", set_key, start, stop) }
|
30
|
+
end
|
31
|
+
|
32
|
+
def zrangebyscore(set_key, min, max)
|
33
|
+
redis { |r| r.call("ZRANGEBYSCORE", set_key, min, max) }
|
34
|
+
end
|
35
|
+
|
36
|
+
def zrem(set_key, key)
|
37
|
+
redis { |r| r.call("ZREM", set_key, key) }
|
38
|
+
end
|
39
|
+
|
40
|
+
def delete(key)
|
41
|
+
redis { |r| r.call("DEL", key) }
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def redis(&block)
|
47
|
+
# Default to Sidekiq.redis if capsule is not configured yet but redis adapter is accessed
|
48
|
+
(@capsule || Sidekiq).redis(&block)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "base"
|
4
|
+
|
5
|
+
module SidekiqStatusMonitor
|
6
|
+
module Redis
|
7
|
+
# Wrapper for `redis` gem used by sidekiq < 7
|
8
|
+
# https://github.com/redis/redis-rb
|
9
|
+
class RedisGem < Base
|
10
|
+
def set(key, time:, ex:)
|
11
|
+
redis { |r| r.set(key, time, ex: ex) }
|
12
|
+
end
|
13
|
+
|
14
|
+
def get(key)
|
15
|
+
redis { |r| r.get(key) }
|
16
|
+
end
|
17
|
+
|
18
|
+
def zadd(set_key, ex, key)
|
19
|
+
redis { |r| r.zadd(set_key, ex, key) }
|
20
|
+
end
|
21
|
+
|
22
|
+
def zrange(set_key, start, stop)
|
23
|
+
redis { |r| r.zrange(set_key, start, stop) }
|
24
|
+
end
|
25
|
+
|
26
|
+
def zrangebyscore(set_key, min, max)
|
27
|
+
redis { |r| r.zrangebyscore(set_key, min, max) }
|
28
|
+
end
|
29
|
+
|
30
|
+
def zrem(set_key, key)
|
31
|
+
redis { |r| r.zrem(set_key, key) }
|
32
|
+
end
|
33
|
+
|
34
|
+
def delete(key)
|
35
|
+
redis { |r| r.del(key) }
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def redis(&block)
|
41
|
+
Sidekiq.redis(&block)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SidekiqStatusMonitor
|
4
|
+
module Redis
|
5
|
+
class << self
|
6
|
+
def adapter
|
7
|
+
Helpers.sidekiq_7 ? Redis::RedisClientGem.new : Redis::RedisGem.new
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
require_relative "redis/base"
|
14
|
+
require_relative "redis/redis_client_gem"
|
15
|
+
require_relative "redis/redis_gem"
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rack"
|
4
|
+
|
5
|
+
module SidekiqStatusMonitor
|
6
|
+
class Server
|
7
|
+
attr_reader :host, :port, :engine, :logger
|
8
|
+
def initialize(host: nil, port: nil, engine: nil, logger: nil, config: nil)
|
9
|
+
@config = config || SidekiqStatusMonitor.config
|
10
|
+
@host = host || @config.host
|
11
|
+
@port = port || @config.port
|
12
|
+
@engine = engine || @config.server
|
13
|
+
@logger = logger || @config.logger
|
14
|
+
end
|
15
|
+
|
16
|
+
def run!
|
17
|
+
handler = Rack::Handler.get(@engine)
|
18
|
+
Signal.trap("TERM") { handler.shutdown }
|
19
|
+
handler.run(
|
20
|
+
self,
|
21
|
+
Port: @port,
|
22
|
+
Host: @host,
|
23
|
+
AccessLog: [],
|
24
|
+
Logger: @logger
|
25
|
+
)
|
26
|
+
end
|
27
|
+
|
28
|
+
def alive?
|
29
|
+
SidekiqStatusMonitor.alive?
|
30
|
+
end
|
31
|
+
|
32
|
+
def payload
|
33
|
+
SidekiqStatusMonitor.info
|
34
|
+
end
|
35
|
+
|
36
|
+
def call(_env)
|
37
|
+
[
|
38
|
+
alive? ? 200 : 500,
|
39
|
+
{ "Content-Type" => "application/json" },
|
40
|
+
[payload.to_json]
|
41
|
+
]
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,144 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "singleton"
|
4
|
+
|
5
|
+
require "sidekiq"
|
6
|
+
require "sidekiq/api"
|
7
|
+
|
8
|
+
require "sidekiq_status_monitor/version"
|
9
|
+
|
10
|
+
require "sidekiq_status_monitor/config"
|
11
|
+
|
12
|
+
require "sidekiq_status_monitor/server"
|
13
|
+
require "sidekiq_status_monitor/redis"
|
14
|
+
require "sidekiq_status_monitor/helpers"
|
15
|
+
|
16
|
+
module SidekiqStatusMonitor
|
17
|
+
CAPSULE_NAME = "sidekiq-status"
|
18
|
+
PROBE_METHOD_PREFIX = "probe_"
|
19
|
+
|
20
|
+
class << self
|
21
|
+
def start
|
22
|
+
Sidekiq.configure_server do |sidekiq_config|
|
23
|
+
sidekiq_config.on(:startup) do
|
24
|
+
logger.info("Starting SidekiqStatusMonitor #{SidekiqStatusMonitor::VERSION}")
|
25
|
+
|
26
|
+
@server_pid = fork do
|
27
|
+
SidekiqStatusMonitor::Server.new.run!
|
28
|
+
end
|
29
|
+
|
30
|
+
logger.info("SidekiqStatusMonitor started, #{config.server} pid #{@server_pid}")
|
31
|
+
end
|
32
|
+
|
33
|
+
sidekiq_config.on(:quiet) do
|
34
|
+
config.shutdown_callback.call
|
35
|
+
end
|
36
|
+
|
37
|
+
sidekiq_config.on(:shutdown) do
|
38
|
+
Process.kill("TERM", @server_pid) unless @server_pid.nil?
|
39
|
+
Process.wait(@server_pid) unless @server_pid.nil?
|
40
|
+
|
41
|
+
config.shutdown_callback.call
|
42
|
+
|
43
|
+
logger.info("SidekiqStatusMonitor stopped")
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def setup
|
49
|
+
yield(config)
|
50
|
+
end
|
51
|
+
|
52
|
+
def redis
|
53
|
+
@redis ||= SidekiqStatusMonitor::Redis.adapter
|
54
|
+
end
|
55
|
+
|
56
|
+
def logger
|
57
|
+
config.logger || Sidekiq.logger
|
58
|
+
end
|
59
|
+
|
60
|
+
def config
|
61
|
+
@config ||= SidekiqStatusMonitor::Config.instance
|
62
|
+
end
|
63
|
+
|
64
|
+
def hostname
|
65
|
+
ENV["HOSTNAME"] || "HOSTNAME_NOT_SET"
|
66
|
+
end
|
67
|
+
|
68
|
+
def workers
|
69
|
+
Sidekiq::Workers.new
|
70
|
+
end
|
71
|
+
|
72
|
+
def workers_size
|
73
|
+
workers.size
|
74
|
+
end
|
75
|
+
|
76
|
+
def process_set
|
77
|
+
Sidekiq::ProcessSet.new
|
78
|
+
end
|
79
|
+
|
80
|
+
def process_set_size
|
81
|
+
process_set.size
|
82
|
+
end
|
83
|
+
|
84
|
+
def queues
|
85
|
+
Sidekiq::Queue.all
|
86
|
+
end
|
87
|
+
|
88
|
+
def queues_size
|
89
|
+
queues.size
|
90
|
+
end
|
91
|
+
|
92
|
+
def queues_avg_latency
|
93
|
+
queues.sum(&:latency) / queues_size if queues_size&.positive?
|
94
|
+
end
|
95
|
+
|
96
|
+
def queues_avg_size
|
97
|
+
queues.sum(&:size) / queues_size if queues_size&.positive?
|
98
|
+
end
|
99
|
+
|
100
|
+
def queues_names
|
101
|
+
queues.map(&:name).uniq.sort
|
102
|
+
end
|
103
|
+
|
104
|
+
def self.new_probe(name, &block)
|
105
|
+
define_method("#{PROBE_METHOD_PREFIX}#{name}", &block)
|
106
|
+
end
|
107
|
+
|
108
|
+
new_probe :workers_size do
|
109
|
+
!config.workers_size_threshold || workers_size && workers_size >= config.workers_size_threshold
|
110
|
+
end
|
111
|
+
|
112
|
+
new_probe :process_set_size do
|
113
|
+
!config.process_set_size_threshold || process_set_size && process_set_size >= config.process_set_size_threshold
|
114
|
+
end
|
115
|
+
|
116
|
+
new_probe :queues_size do
|
117
|
+
!config.queues_size_threshold || queues_size && queues_size >= config.queues_size_threshold
|
118
|
+
end
|
119
|
+
|
120
|
+
new_probe :queue_avg_latency do
|
121
|
+
!config.queue_latency_threshold || queues_avg_latency && queues_avg_latency < config.queue_latency_threshold
|
122
|
+
end
|
123
|
+
|
124
|
+
new_probe :queue_avg_size do
|
125
|
+
!config.queue_size_threshold || queues_avg_size && queues_avg_size < config.queue_size_threshold
|
126
|
+
end
|
127
|
+
|
128
|
+
def probes
|
129
|
+
methods.grep(/^#{PROBE_METHOD_PREFIX}/).map { |m| [m, send(m)] }.to_h
|
130
|
+
end
|
131
|
+
|
132
|
+
def alive?
|
133
|
+
probes.values.all? { |v| v == true }
|
134
|
+
end
|
135
|
+
|
136
|
+
def info
|
137
|
+
probes.merge(
|
138
|
+
alive: alive?
|
139
|
+
)
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
SidekiqStatusMonitor.start unless ENV.fetch("DISABLE_SIDEKIQ_STATUS", "")&.to_s&.gsub(/true|1/i, "true") == "true"
|
metadata
ADDED
@@ -0,0 +1,230 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: sidekiq_status_monitor
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Andrei Makarov
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2023-10-12 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.16'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.16'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: debug
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.6'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.6'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rack-test
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 2.1.0
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 2.1.0
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rake
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '13.0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '13.0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rspec
|
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: rspec-sidekiq
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '4.0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '4.0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rubocop-shopify
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '2.10'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '2.10'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: solargraph
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: 0.49.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.49.0
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: rack
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - "<"
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '3'
|
132
|
+
type: :runtime
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - "<"
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '3'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: sidekiq
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ">="
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '5'
|
146
|
+
- - "<"
|
147
|
+
- !ruby/object:Gem::Version
|
148
|
+
version: '8'
|
149
|
+
type: :runtime
|
150
|
+
prerelease: false
|
151
|
+
version_requirements: !ruby/object:Gem::Requirement
|
152
|
+
requirements:
|
153
|
+
- - ">="
|
154
|
+
- !ruby/object:Gem::Version
|
155
|
+
version: '5'
|
156
|
+
- - "<"
|
157
|
+
- !ruby/object:Gem::Version
|
158
|
+
version: '8'
|
159
|
+
- !ruby/object:Gem::Dependency
|
160
|
+
name: webrick
|
161
|
+
requirement: !ruby/object:Gem::Requirement
|
162
|
+
requirements:
|
163
|
+
- - ">="
|
164
|
+
- !ruby/object:Gem::Version
|
165
|
+
version: '1'
|
166
|
+
- - "<"
|
167
|
+
- !ruby/object:Gem::Version
|
168
|
+
version: '2'
|
169
|
+
type: :runtime
|
170
|
+
prerelease: false
|
171
|
+
version_requirements: !ruby/object:Gem::Requirement
|
172
|
+
requirements:
|
173
|
+
- - ">="
|
174
|
+
- !ruby/object:Gem::Version
|
175
|
+
version: '1'
|
176
|
+
- - "<"
|
177
|
+
- !ruby/object:Gem::Version
|
178
|
+
version: '2'
|
179
|
+
description: |
|
180
|
+
SidekiqStatusMonitor offers a solution to add HTTP server for the sidekiq instance.
|
181
|
+
|
182
|
+
Can be used for Kubernetes livenessProbe and readinessProbe checks.
|
183
|
+
Other liveness/alive checks can be done too since the server returns 200/500 status codes.
|
184
|
+
|
185
|
+
Also provides a HTTP JSON interface for crawling metrics.
|
186
|
+
email:
|
187
|
+
- andrei@kiskolabs.com
|
188
|
+
executables: []
|
189
|
+
extensions: []
|
190
|
+
extra_rdoc_files: []
|
191
|
+
files:
|
192
|
+
- README.md
|
193
|
+
- lib/sidekiq_status_monitor.rb
|
194
|
+
- lib/sidekiq_status_monitor/config.rb
|
195
|
+
- lib/sidekiq_status_monitor/helpers.rb
|
196
|
+
- lib/sidekiq_status_monitor/redis.rb
|
197
|
+
- lib/sidekiq_status_monitor/redis/base.rb
|
198
|
+
- lib/sidekiq_status_monitor/redis/redis_client_gem.rb
|
199
|
+
- lib/sidekiq_status_monitor/redis/redis_gem.rb
|
200
|
+
- lib/sidekiq_status_monitor/server.rb
|
201
|
+
- lib/sidekiq_status_monitor/version.rb
|
202
|
+
homepage: https://github.com/amkisko/sidekiq_status_monitor
|
203
|
+
licenses:
|
204
|
+
- MIT
|
205
|
+
metadata:
|
206
|
+
homepage_uri: https://github.com/amkisko/sidekiq_status_monitor
|
207
|
+
source_code_uri: https://github.com/amkisko/sidekiq_status_monitor
|
208
|
+
changelog_uri: https://github.com/amkisko/sidekiq_status_monitor/releases
|
209
|
+
documentation_uri: https://github.com/amkisko/sidekiq_status_monitor/blob/v1.0.0/README.md
|
210
|
+
bug_tracker_uri: https://github.com/amkisko/sidekiq_status_monitor/issues
|
211
|
+
post_install_message:
|
212
|
+
rdoc_options: []
|
213
|
+
require_paths:
|
214
|
+
- lib
|
215
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
216
|
+
requirements:
|
217
|
+
- - ">="
|
218
|
+
- !ruby/object:Gem::Version
|
219
|
+
version: 2.7.0
|
220
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
221
|
+
requirements:
|
222
|
+
- - ">="
|
223
|
+
- !ruby/object:Gem::Version
|
224
|
+
version: '0'
|
225
|
+
requirements: []
|
226
|
+
rubygems_version: 3.4.19
|
227
|
+
signing_key:
|
228
|
+
specification_version: 4
|
229
|
+
summary: Sidekiq status web server extension.
|
230
|
+
test_files: []
|