lepus 0.0.1.rc2 → 0.1.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 +4 -4
- data/.gitignore +0 -1
- data/Gemfile +5 -0
- data/Gemfile.lock +12 -1
- data/README.md +179 -0
- data/config.ru +14 -0
- data/docs/README.md +80 -0
- data/docs/cli.md +108 -0
- data/docs/configuration.md +171 -0
- data/docs/consumers.md +168 -0
- data/docs/getting-started.md +136 -0
- data/docs/images/lepus-web.png +0 -0
- data/docs/middleware.md +240 -0
- data/docs/producers.md +173 -0
- data/docs/prometheus.md +112 -0
- data/docs/rails.md +161 -0
- data/docs/supervisor.md +112 -0
- data/docs/testing.md +141 -0
- data/docs/web.md +85 -0
- data/examples/grafana-dashboard.json +450 -0
- data/gemfiles/Gemfile.rails-5.2 +1 -0
- data/gemfiles/Gemfile.rails-5.2.lock +59 -46
- data/gemfiles/Gemfile.rails-6.1 +1 -0
- data/gemfiles/Gemfile.rails-6.1.lock +72 -58
- data/gemfiles/Gemfile.rails-7.2.lock +8 -1
- data/gemfiles/Gemfile.rails-8.0.lock +8 -1
- data/lepus.gemspec +5 -1
- data/lib/lepus/cli.rb +24 -0
- data/lib/lepus/configuration.rb +42 -0
- data/lib/lepus/consumer.rb +12 -0
- data/lib/lepus/consumers/handler.rb +3 -1
- data/lib/lepus/consumers/stats.rb +70 -0
- data/lib/lepus/consumers/stats_registry.rb +29 -0
- data/lib/lepus/consumers/worker.rb +7 -6
- data/lib/lepus/process.rb +4 -4
- data/lib/lepus/process_registry/backend.rb +49 -0
- data/lib/lepus/process_registry/file_backend.rb +108 -0
- data/lib/lepus/process_registry/message_builder.rb +72 -0
- data/lib/lepus/process_registry/rabbitmq_backend.rb +153 -0
- data/lib/lepus/process_registry.rb +28 -67
- data/lib/lepus/prometheus/collector.rb +149 -0
- data/lib/lepus/prometheus/instrumentation.rb +168 -0
- data/lib/lepus/prometheus.rb +48 -0
- data/lib/lepus/publisher.rb +3 -1
- data/lib/lepus/supervisor.rb +9 -2
- data/lib/lepus/version.rb +1 -1
- data/lib/lepus/web/aggregator.rb +154 -0
- data/lib/lepus/web/api.rb +132 -0
- data/lib/lepus/web/app.rb +37 -0
- data/lib/lepus/web/management_api.rb +192 -0
- data/lib/lepus/web/respond_with.rb +28 -0
- data/lib/lepus/web.rb +238 -0
- data/lib/lepus.rb +5 -0
- data/test_offline.html +189 -0
- data/web/assets/css/styles.css +635 -0
- data/web/assets/js/app.js +6 -0
- data/web/assets/js/bootstrap.js +20 -0
- data/web/assets/js/controllers/connection_controller.js +44 -0
- data/web/assets/js/controllers/dashboard_controller.js +499 -0
- data/web/assets/js/controllers/queue_controller.js +17 -0
- data/web/assets/js/controllers/theme_controller.js +31 -0
- data/web/assets/js/offline-manager.js +233 -0
- data/web/assets/js/service-worker-manager.js +65 -0
- data/web/index.html +159 -0
- data/web/sw.js +144 -0
- metadata +103 -5
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: ..
|
|
3
3
|
specs:
|
|
4
|
-
lepus (0.
|
|
4
|
+
lepus (0.1.0)
|
|
5
|
+
base64
|
|
5
6
|
bunny
|
|
6
7
|
concurrent-ruby
|
|
7
8
|
multi_json
|
|
@@ -70,54 +71,57 @@ GEM
|
|
|
70
71
|
minitest (>= 5.1)
|
|
71
72
|
tzinfo (~> 2.0)
|
|
72
73
|
zeitwerk (~> 2.3)
|
|
73
|
-
addressable (2.
|
|
74
|
-
public_suffix (>= 2.0.2, <
|
|
75
|
-
amq-protocol (2.
|
|
74
|
+
addressable (2.9.0)
|
|
75
|
+
public_suffix (>= 2.0.2, < 8.0)
|
|
76
|
+
amq-protocol (2.7.0)
|
|
76
77
|
ast (2.4.3)
|
|
77
78
|
base64 (0.3.0)
|
|
78
|
-
bigdecimal (
|
|
79
|
+
bigdecimal (4.1.1)
|
|
79
80
|
builder (3.3.0)
|
|
80
|
-
bunny (
|
|
81
|
-
amq-protocol (~> 2.
|
|
81
|
+
bunny (3.1.0)
|
|
82
|
+
amq-protocol (~> 2.7)
|
|
83
|
+
logger (~> 1, >= 1.7)
|
|
82
84
|
sorted_set (~> 1, >= 1.0.2)
|
|
83
85
|
coderay (1.1.3)
|
|
84
|
-
concurrent-ruby (1.3.
|
|
86
|
+
concurrent-ruby (1.3.6)
|
|
85
87
|
connection_pool (2.5.5)
|
|
86
|
-
crack (1.0.
|
|
88
|
+
crack (1.0.1)
|
|
87
89
|
bigdecimal
|
|
88
90
|
rexml
|
|
89
91
|
crass (1.0.6)
|
|
90
|
-
date (3.
|
|
92
|
+
date (3.5.1)
|
|
91
93
|
de-dupe (0.0.2)
|
|
92
94
|
redis
|
|
93
95
|
zeitwerk
|
|
94
96
|
diff-lcs (1.6.2)
|
|
95
97
|
docile (1.4.1)
|
|
96
|
-
dotenv (2.
|
|
98
|
+
dotenv (3.2.0)
|
|
97
99
|
erubi (1.13.1)
|
|
98
|
-
globalid (1.
|
|
100
|
+
globalid (1.3.0)
|
|
99
101
|
activesupport (>= 6.1)
|
|
100
|
-
hashdiff (1.2.
|
|
101
|
-
i18n (1.14.
|
|
102
|
+
hashdiff (1.2.1)
|
|
103
|
+
i18n (1.14.8)
|
|
102
104
|
concurrent-ruby (~> 1.0)
|
|
103
|
-
|
|
105
|
+
io-console (0.8.2)
|
|
106
|
+
json (2.19.3)
|
|
104
107
|
language_server-protocol (3.17.0.5)
|
|
105
108
|
lint_roller (1.1.0)
|
|
106
109
|
logger (1.7.0)
|
|
107
|
-
loofah (2.
|
|
110
|
+
loofah (2.25.1)
|
|
108
111
|
crass (~> 1.0.2)
|
|
109
112
|
nokogiri (>= 1.12.0)
|
|
110
|
-
mail (2.
|
|
113
|
+
mail (2.9.0)
|
|
114
|
+
logger
|
|
111
115
|
mini_mime (>= 0.1.1)
|
|
112
116
|
net-imap
|
|
113
117
|
net-pop
|
|
114
118
|
net-smtp
|
|
115
|
-
marcel (1.0
|
|
119
|
+
marcel (1.1.0)
|
|
116
120
|
method_source (1.1.0)
|
|
117
121
|
mini_mime (1.1.5)
|
|
118
|
-
minitest (5.
|
|
122
|
+
minitest (5.26.1)
|
|
119
123
|
multi_json (1.19.1)
|
|
120
|
-
net-imap (0.4.
|
|
124
|
+
net-imap (0.4.23)
|
|
121
125
|
date
|
|
122
126
|
net-protocol
|
|
123
127
|
net-pop (0.1.2)
|
|
@@ -126,20 +130,23 @@ GEM
|
|
|
126
130
|
timeout
|
|
127
131
|
net-smtp (0.5.1)
|
|
128
132
|
net-protocol
|
|
129
|
-
nio4r (2.7.
|
|
130
|
-
nokogiri (1.
|
|
133
|
+
nio4r (2.7.5)
|
|
134
|
+
nokogiri (1.17.2-x86_64-linux)
|
|
131
135
|
racc (~> 1.4)
|
|
132
|
-
parallel (1.
|
|
133
|
-
parser (3.3.
|
|
136
|
+
parallel (1.28.0)
|
|
137
|
+
parser (3.3.11.1)
|
|
134
138
|
ast (~> 2.4.1)
|
|
135
139
|
racc
|
|
136
|
-
prism (1.
|
|
137
|
-
|
|
140
|
+
prism (1.9.0)
|
|
141
|
+
prometheus_exporter (2.2.0)
|
|
142
|
+
webrick
|
|
143
|
+
pry (0.16.0)
|
|
138
144
|
coderay (~> 1.1)
|
|
139
145
|
method_source (~> 1.0)
|
|
140
|
-
|
|
146
|
+
reline (>= 0.6.0)
|
|
147
|
+
public_suffix (6.0.2)
|
|
141
148
|
racc (1.8.1)
|
|
142
|
-
rack (2.2.
|
|
149
|
+
rack (2.2.23)
|
|
143
150
|
rack-test (2.2.0)
|
|
144
151
|
rack (>= 1.3)
|
|
145
152
|
rails (6.1.7.10)
|
|
@@ -161,8 +168,8 @@ GEM
|
|
|
161
168
|
activesupport (>= 5.0.0)
|
|
162
169
|
minitest
|
|
163
170
|
nokogiri (>= 1.6)
|
|
164
|
-
rails-html-sanitizer (1.
|
|
165
|
-
loofah (~> 2.
|
|
171
|
+
rails-html-sanitizer (1.7.0)
|
|
172
|
+
loofah (~> 2.25)
|
|
166
173
|
nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0)
|
|
167
174
|
railties (6.1.7.10)
|
|
168
175
|
actionpack (= 6.1.7.10)
|
|
@@ -171,28 +178,30 @@ GEM
|
|
|
171
178
|
rake (>= 12.2)
|
|
172
179
|
thor (~> 1.0)
|
|
173
180
|
rainbow (3.1.1)
|
|
174
|
-
rake (13.
|
|
181
|
+
rake (13.4.2)
|
|
175
182
|
rbtree (0.4.6)
|
|
176
183
|
redis (5.4.1)
|
|
177
184
|
redis-client (>= 0.22.0)
|
|
178
|
-
redis-client (0.
|
|
185
|
+
redis-client (0.28.0)
|
|
179
186
|
connection_pool
|
|
180
|
-
regexp_parser (2.
|
|
181
|
-
|
|
182
|
-
|
|
187
|
+
regexp_parser (2.12.0)
|
|
188
|
+
reline (0.6.3)
|
|
189
|
+
io-console (~> 0.5)
|
|
190
|
+
rexml (3.4.4)
|
|
191
|
+
rspec (3.13.2)
|
|
183
192
|
rspec-core (~> 3.13.0)
|
|
184
193
|
rspec-expectations (~> 3.13.0)
|
|
185
194
|
rspec-mocks (~> 3.13.0)
|
|
186
|
-
rspec-core (3.13.
|
|
195
|
+
rspec-core (3.13.6)
|
|
187
196
|
rspec-support (~> 3.13.0)
|
|
188
197
|
rspec-expectations (3.13.5)
|
|
189
198
|
diff-lcs (>= 1.2.0, < 2.0)
|
|
190
199
|
rspec-support (~> 3.13.0)
|
|
191
|
-
rspec-mocks (3.13.
|
|
200
|
+
rspec-mocks (3.13.8)
|
|
192
201
|
diff-lcs (>= 1.2.0, < 2.0)
|
|
193
202
|
rspec-support (~> 3.13.0)
|
|
194
|
-
rspec-support (3.13.
|
|
195
|
-
rubocop (1.
|
|
203
|
+
rspec-support (3.13.7)
|
|
204
|
+
rubocop (1.84.2)
|
|
196
205
|
json (~> 2.3)
|
|
197
206
|
language_server-protocol (~> 3.17.0.2)
|
|
198
207
|
lint_roller (~> 1.1.0)
|
|
@@ -200,18 +209,19 @@ GEM
|
|
|
200
209
|
parser (>= 3.3.0.2)
|
|
201
210
|
rainbow (>= 2.2.2, < 4.0)
|
|
202
211
|
regexp_parser (>= 2.9.3, < 3.0)
|
|
203
|
-
rubocop-ast (>= 1.
|
|
212
|
+
rubocop-ast (>= 1.49.0, < 2.0)
|
|
204
213
|
ruby-progressbar (~> 1.7)
|
|
205
214
|
unicode-display_width (>= 2.4.0, < 4.0)
|
|
206
|
-
rubocop-ast (1.
|
|
215
|
+
rubocop-ast (1.49.1)
|
|
207
216
|
parser (>= 3.3.7.2)
|
|
208
|
-
prism (~> 1.
|
|
209
|
-
rubocop-performance (1.
|
|
210
|
-
|
|
211
|
-
rubocop
|
|
212
|
-
|
|
217
|
+
prism (~> 1.7)
|
|
218
|
+
rubocop-performance (1.26.1)
|
|
219
|
+
lint_roller (~> 1.1)
|
|
220
|
+
rubocop (>= 1.75.0, < 2.0)
|
|
221
|
+
rubocop-ast (>= 1.47.1, < 2.0)
|
|
222
|
+
rubocop-rspec (3.9.0)
|
|
213
223
|
lint_roller (~> 1.1)
|
|
214
|
-
rubocop (~> 1.
|
|
224
|
+
rubocop (~> 1.81)
|
|
215
225
|
ruby-progressbar (1.13.0)
|
|
216
226
|
simplecov (0.22.0)
|
|
217
227
|
docile (~> 1.1)
|
|
@@ -229,29 +239,30 @@ GEM
|
|
|
229
239
|
actionpack (>= 6.1)
|
|
230
240
|
activesupport (>= 6.1)
|
|
231
241
|
sprockets (>= 3.0.0)
|
|
232
|
-
standard (1.
|
|
242
|
+
standard (1.54.0)
|
|
233
243
|
language_server-protocol (~> 3.17.0.2)
|
|
234
244
|
lint_roller (~> 1.0)
|
|
235
|
-
rubocop (~> 1.
|
|
245
|
+
rubocop (~> 1.84.0)
|
|
236
246
|
standard-custom (~> 1.0.0)
|
|
237
|
-
standard-performance (~> 1.
|
|
247
|
+
standard-performance (~> 1.8)
|
|
238
248
|
standard-custom (1.0.2)
|
|
239
249
|
lint_roller (~> 1.0)
|
|
240
250
|
rubocop (~> 1.50)
|
|
241
|
-
standard-performance (1.
|
|
251
|
+
standard-performance (1.9.0)
|
|
242
252
|
lint_roller (~> 1.1)
|
|
243
|
-
rubocop-performance (~> 1.
|
|
244
|
-
thor (1.
|
|
245
|
-
timeout (0.
|
|
253
|
+
rubocop-performance (~> 1.26.0)
|
|
254
|
+
thor (1.5.0)
|
|
255
|
+
timeout (0.6.1)
|
|
246
256
|
tzinfo (2.0.6)
|
|
247
257
|
concurrent-ruby (~> 1.0)
|
|
248
|
-
unicode-display_width (3.
|
|
249
|
-
unicode-emoji (~> 4.
|
|
250
|
-
unicode-emoji (4.0
|
|
251
|
-
webmock (3.
|
|
258
|
+
unicode-display_width (3.2.0)
|
|
259
|
+
unicode-emoji (~> 4.1)
|
|
260
|
+
unicode-emoji (4.2.0)
|
|
261
|
+
webmock (3.26.2)
|
|
252
262
|
addressable (>= 2.8.0)
|
|
253
263
|
crack (>= 0.3.2)
|
|
254
264
|
hashdiff (>= 0.4.0, < 2.0.0)
|
|
265
|
+
webrick (1.9.2)
|
|
255
266
|
websocket-driver (0.8.0)
|
|
256
267
|
base64
|
|
257
268
|
websocket-extensions (>= 0.1.0)
|
|
@@ -266,7 +277,10 @@ DEPENDENCIES
|
|
|
266
277
|
de-dupe
|
|
267
278
|
dotenv
|
|
268
279
|
lepus!
|
|
280
|
+
prometheus_exporter (< 2.3)
|
|
269
281
|
pry
|
|
282
|
+
rack (>= 2.2)
|
|
283
|
+
rack-test
|
|
270
284
|
rails (~> 6.1, >= 6.1.7.10)
|
|
271
285
|
rspec
|
|
272
286
|
rubocop
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: ..
|
|
3
3
|
specs:
|
|
4
|
-
lepus (0.
|
|
4
|
+
lepus (0.1.0)
|
|
5
|
+
base64
|
|
5
6
|
bunny
|
|
6
7
|
concurrent-ruby
|
|
7
8
|
multi_json
|
|
@@ -157,6 +158,8 @@ GEM
|
|
|
157
158
|
prettyprint
|
|
158
159
|
prettyprint (0.2.0)
|
|
159
160
|
prism (1.4.0)
|
|
161
|
+
prometheus_exporter (2.3.1)
|
|
162
|
+
webrick
|
|
160
163
|
pry (0.15.2)
|
|
161
164
|
coderay (~> 1.1)
|
|
162
165
|
method_source (~> 1.0)
|
|
@@ -287,6 +290,7 @@ GEM
|
|
|
287
290
|
addressable (>= 2.8.0)
|
|
288
291
|
crack (>= 0.3.2)
|
|
289
292
|
hashdiff (>= 0.4.0, < 2.0.0)
|
|
293
|
+
webrick (1.9.2)
|
|
290
294
|
websocket-driver (0.8.0)
|
|
291
295
|
base64
|
|
292
296
|
websocket-extensions (>= 0.1.0)
|
|
@@ -300,7 +304,10 @@ DEPENDENCIES
|
|
|
300
304
|
de-dupe
|
|
301
305
|
dotenv
|
|
302
306
|
lepus!
|
|
307
|
+
prometheus_exporter
|
|
303
308
|
pry
|
|
309
|
+
rack (>= 2.2)
|
|
310
|
+
rack-test
|
|
304
311
|
rails (~> 7.2, >= 7.2.2.2)
|
|
305
312
|
rspec
|
|
306
313
|
rubocop
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: ..
|
|
3
3
|
specs:
|
|
4
|
-
lepus (0.
|
|
4
|
+
lepus (0.1.0)
|
|
5
|
+
base64
|
|
5
6
|
bunny
|
|
6
7
|
concurrent-ruby
|
|
7
8
|
multi_json
|
|
@@ -157,6 +158,8 @@ GEM
|
|
|
157
158
|
prettyprint
|
|
158
159
|
prettyprint (0.2.0)
|
|
159
160
|
prism (1.4.0)
|
|
161
|
+
prometheus_exporter (2.3.1)
|
|
162
|
+
webrick
|
|
160
163
|
pry (0.15.2)
|
|
161
164
|
coderay (~> 1.1)
|
|
162
165
|
method_source (~> 1.0)
|
|
@@ -288,6 +291,7 @@ GEM
|
|
|
288
291
|
addressable (>= 2.8.0)
|
|
289
292
|
crack (>= 0.3.2)
|
|
290
293
|
hashdiff (>= 0.4.0, < 2.0.0)
|
|
294
|
+
webrick (1.9.2)
|
|
291
295
|
websocket-driver (0.8.0)
|
|
292
296
|
base64
|
|
293
297
|
websocket-extensions (>= 0.1.0)
|
|
@@ -301,7 +305,10 @@ DEPENDENCIES
|
|
|
301
305
|
de-dupe
|
|
302
306
|
dotenv
|
|
303
307
|
lepus!
|
|
308
|
+
prometheus_exporter
|
|
304
309
|
pry
|
|
310
|
+
rack (>= 2.2)
|
|
311
|
+
rack-test
|
|
305
312
|
rails (~> 8.0, >= 8.0.2.1)
|
|
306
313
|
rspec
|
|
307
314
|
rubocop
|
data/lepus.gemspec
CHANGED
|
@@ -12,7 +12,7 @@ Gem::Specification.new do |spec|
|
|
|
12
12
|
RabbitMQ consumers/producer for ruby applications
|
|
13
13
|
SUMMARY
|
|
14
14
|
spec.description = <<~DESCRIPTION
|
|
15
|
-
RabbitMQ consumers/producer for ruby
|
|
15
|
+
RabbitMQ consumers/producer for ruby applications
|
|
16
16
|
DESCRIPTION
|
|
17
17
|
|
|
18
18
|
spec.homepage = "https://github.com/marcosgz/lepus"
|
|
@@ -36,6 +36,7 @@ Gem::Specification.new do |spec|
|
|
|
36
36
|
spec.executables = spec.files.grep(%r{^exec/}) { |f| File.basename(f) }
|
|
37
37
|
spec.require_paths = ["lib"]
|
|
38
38
|
|
|
39
|
+
spec.add_dependency "base64", ">= 0.0.0"
|
|
39
40
|
spec.add_dependency "bunny", ">= 0.0.0"
|
|
40
41
|
spec.add_dependency "thor", ">= 0.0.0"
|
|
41
42
|
spec.add_dependency "zeitwerk", ">= 0.0.0"
|
|
@@ -44,6 +45,8 @@ Gem::Specification.new do |spec|
|
|
|
44
45
|
|
|
45
46
|
spec.add_development_dependency "dotenv"
|
|
46
47
|
spec.add_development_dependency "pry"
|
|
48
|
+
spec.add_development_dependency "rack", ">= 2.2"
|
|
49
|
+
spec.add_development_dependency "rack-test"
|
|
47
50
|
spec.add_development_dependency "rspec"
|
|
48
51
|
spec.add_development_dependency "rubocop"
|
|
49
52
|
spec.add_development_dependency "rubocop-performance"
|
|
@@ -52,4 +55,5 @@ Gem::Specification.new do |spec|
|
|
|
52
55
|
spec.add_development_dependency "webmock"
|
|
53
56
|
spec.add_development_dependency "simplecov"
|
|
54
57
|
spec.add_development_dependency "de-dupe"
|
|
58
|
+
spec.add_development_dependency "prometheus_exporter"
|
|
55
59
|
end
|
data/lib/lepus/cli.rb
CHANGED
|
@@ -30,5 +30,29 @@ module Lepus
|
|
|
30
30
|
|
|
31
31
|
Lepus::Supervisor.start(**opts)
|
|
32
32
|
end
|
|
33
|
+
|
|
34
|
+
desc "web", "Run Lepus Web dashboard"
|
|
35
|
+
method_option :port, type: :numeric, aliases: "-p", default: 9292, desc: "Port to listen on"
|
|
36
|
+
method_option :host, type: :string, aliases: "-o", default: "0.0.0.0", desc: "Host to bind"
|
|
37
|
+
def web
|
|
38
|
+
port = (options[:port] || 9292).to_i
|
|
39
|
+
host = options[:host] || "0.0.0.0"
|
|
40
|
+
|
|
41
|
+
puts "Starting Lepus Web dashboard on http://#{host}:#{port}"
|
|
42
|
+
puts "Press Ctrl+C to stop"
|
|
43
|
+
|
|
44
|
+
if system("which rackup > /dev/null 2>&1")
|
|
45
|
+
|
|
46
|
+
exec "rackup -p #{port} -o #{host} #{__dir__}/../../config.ru"
|
|
47
|
+
else
|
|
48
|
+
puts <<~MSG
|
|
49
|
+
Rack is not installed. Please install it using the following command:
|
|
50
|
+
|
|
51
|
+
gem install rack
|
|
52
|
+
|
|
53
|
+
Then run the web dashboard again.
|
|
54
|
+
MSG
|
|
55
|
+
end
|
|
56
|
+
end
|
|
33
57
|
end
|
|
34
58
|
end
|
data/lib/lepus/configuration.rb
CHANGED
|
@@ -40,6 +40,27 @@ module Lepus
|
|
|
40
40
|
# @return [Integer] the threshold in seconds to consider a process alive. Default is 5 minutes.
|
|
41
41
|
attr_accessor :process_alive_threshold
|
|
42
42
|
|
|
43
|
+
# @return [Symbol] the process registry backend to use (:file or :rabbitmq). Default is :file.
|
|
44
|
+
attr_accessor :process_registry_backend
|
|
45
|
+
|
|
46
|
+
# @return [String, nil] the application name shown in the web dashboard.
|
|
47
|
+
# Falls back to {#connection_name} when not explicitly set so that hosts
|
|
48
|
+
# that only configure `connection_name` still group correctly in the UI.
|
|
49
|
+
attr_writer :application_name
|
|
50
|
+
|
|
51
|
+
def application_name
|
|
52
|
+
@application_name || connection_name
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# @return [String, nil] the RabbitMQ Management API URL.
|
|
56
|
+
attr_accessor :management_api_url
|
|
57
|
+
|
|
58
|
+
# @return [Array<Numeric>] histogram buckets (in seconds) used by the
|
|
59
|
+
# prometheus_exporter collector for delivery and publish latency.
|
|
60
|
+
attr_accessor :prometheus_buckets
|
|
61
|
+
|
|
62
|
+
DEFAULT_PROMETHEUS_BUCKETS = [0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10].freeze
|
|
63
|
+
|
|
43
64
|
def initialize
|
|
44
65
|
@connection_name = "Lepus (#{Lepus::VERSION})"
|
|
45
66
|
@rabbitmq_url = ENV.fetch("RABBITMQ_URL", DEFAULT_RABBITMQ_URL) || DEFAULT_RABBITMQ_URL
|
|
@@ -49,6 +70,27 @@ module Lepus
|
|
|
49
70
|
@consumers_directory = DEFAULT_CONSUMERS_DIRECTORY
|
|
50
71
|
@process_heartbeat_interval = 60
|
|
51
72
|
@process_alive_threshold = 5 * 60
|
|
73
|
+
@process_registry_backend = :file
|
|
74
|
+
@application_name = nil
|
|
75
|
+
@management_api_url = nil
|
|
76
|
+
@prometheus_buckets = DEFAULT_PROMETHEUS_BUCKETS
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# Builds the process registry backend based on configuration.
|
|
80
|
+
# @return [Lepus::ProcessRegistry::Backend] the configured backend
|
|
81
|
+
def build_process_registry_backend
|
|
82
|
+
case process_registry_backend
|
|
83
|
+
when :rabbitmq
|
|
84
|
+
ProcessRegistry::RabbitmqBackend.new
|
|
85
|
+
else
|
|
86
|
+
ProcessRegistry::FileBackend.new
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Builds the Management API client based on configuration.
|
|
91
|
+
# @return [Lepus::Web::ManagementAPI] the management API client
|
|
92
|
+
def build_management_api
|
|
93
|
+
Web::ManagementAPI.new(base_url: management_api_url)
|
|
52
94
|
end
|
|
53
95
|
|
|
54
96
|
# @param suffix [String] the suffix to add to the connection name
|
data/lib/lepus/consumer.rb
CHANGED
|
@@ -103,6 +103,7 @@ module Lepus
|
|
|
103
103
|
rescue Lepus::InvalidConsumerReturnError
|
|
104
104
|
raise
|
|
105
105
|
rescue Exception # rubocop:disable Lint/RescueException
|
|
106
|
+
on_delivery_error
|
|
106
107
|
# In testing mode, re-raise exceptions if consumer_raise_errors? is enabled
|
|
107
108
|
if defined?(Lepus::Testing) && Lepus::Testing.consumer_raise_errors?
|
|
108
109
|
raise
|
|
@@ -111,6 +112,12 @@ module Lepus
|
|
|
111
112
|
reject!
|
|
112
113
|
end
|
|
113
114
|
|
|
115
|
+
# Returns whether the last delivery resulted in an error.
|
|
116
|
+
# Always false in core; overridden by Lepus::Web when loaded.
|
|
117
|
+
def last_delivery_errored?
|
|
118
|
+
false
|
|
119
|
+
end
|
|
120
|
+
|
|
114
121
|
protected
|
|
115
122
|
|
|
116
123
|
def logger
|
|
@@ -174,6 +181,11 @@ module Lepus
|
|
|
174
181
|
end
|
|
175
182
|
end
|
|
176
183
|
|
|
184
|
+
# Hook called when a delivery raises an exception.
|
|
185
|
+
# No-op in core; overridden by Lepus::Web to track error state.
|
|
186
|
+
def on_delivery_error
|
|
187
|
+
end
|
|
188
|
+
|
|
177
189
|
def verify_result(result)
|
|
178
190
|
return if %i[ack reject requeue nack].include?(result)
|
|
179
191
|
|
|
@@ -22,7 +22,9 @@ module Lepus
|
|
|
22
22
|
def process_delivery(delivery_info, metadata, payload)
|
|
23
23
|
consumer
|
|
24
24
|
.process_delivery(delivery_info, metadata, payload)
|
|
25
|
-
.tap
|
|
25
|
+
.tap do |result|
|
|
26
|
+
process_result(result, delivery_info.delivery_tag)
|
|
27
|
+
end
|
|
26
28
|
end
|
|
27
29
|
|
|
28
30
|
private
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "concurrent"
|
|
4
|
+
|
|
5
|
+
module Lepus
|
|
6
|
+
module Consumers
|
|
7
|
+
# Thread-safe per-consumer-class statistics tracker.
|
|
8
|
+
# Uses atomic counters to track processed/rejected/errored message counts.
|
|
9
|
+
class Stats
|
|
10
|
+
attr_reader :consumer_class
|
|
11
|
+
|
|
12
|
+
def initialize(consumer_class)
|
|
13
|
+
@consumer_class = consumer_class
|
|
14
|
+
@processed = Concurrent::AtomicFixnum.new(0)
|
|
15
|
+
@rejected = Concurrent::AtomicFixnum.new(0)
|
|
16
|
+
@errored = Concurrent::AtomicFixnum.new(0)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def record_processed
|
|
20
|
+
@processed.increment
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def record_rejected
|
|
24
|
+
@rejected.increment
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def record_errored
|
|
28
|
+
@errored.increment
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def processed
|
|
32
|
+
@processed.value
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def rejected
|
|
36
|
+
@rejected.value
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def errored
|
|
40
|
+
@errored.value
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def to_h
|
|
44
|
+
config = consumer_class.config
|
|
45
|
+
{
|
|
46
|
+
class_name: consumer_class.name,
|
|
47
|
+
exchange: config.exchange_name,
|
|
48
|
+
queue: config.queue_name,
|
|
49
|
+
route: extract_route(config),
|
|
50
|
+
threads: config.worker_threads,
|
|
51
|
+
processed: @processed.value,
|
|
52
|
+
rejected: @rejected.value,
|
|
53
|
+
errored: @errored.value
|
|
54
|
+
}
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
private
|
|
58
|
+
|
|
59
|
+
def extract_route(config)
|
|
60
|
+
binds = config.binds_args
|
|
61
|
+
return nil if binds.empty?
|
|
62
|
+
|
|
63
|
+
keys = binds.filter_map { |b| b[:routing_key] }
|
|
64
|
+
return nil if keys.empty?
|
|
65
|
+
|
|
66
|
+
(keys.length == 1) ? keys.first : keys
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "concurrent"
|
|
4
|
+
|
|
5
|
+
module Lepus
|
|
6
|
+
module Consumers
|
|
7
|
+
# Per-worker registry of consumer stats.
|
|
8
|
+
# Uses Concurrent::Map for thread-safe lazy initialization.
|
|
9
|
+
class StatsRegistry
|
|
10
|
+
def initialize
|
|
11
|
+
@stats = Concurrent::Map.new
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def for(consumer_class)
|
|
15
|
+
@stats.compute_if_absent(consumer_class.name) do
|
|
16
|
+
Stats.new(consumer_class)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def all
|
|
21
|
+
@stats.values.map(&:to_h)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def connection_count
|
|
25
|
+
@stats.size
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -110,12 +110,7 @@ module Lepus
|
|
|
110
110
|
main_queue.bind(exchange, **opts)
|
|
111
111
|
end
|
|
112
112
|
|
|
113
|
-
consumer_handler =
|
|
114
|
-
consumer_class,
|
|
115
|
-
channel,
|
|
116
|
-
main_queue,
|
|
117
|
-
"#{consumer_class.name}-#{n + 1}"
|
|
118
|
-
)
|
|
113
|
+
consumer_handler = build_handler(consumer_class, channel, main_queue, "#{consumer_class.name}-#{n + 1}")
|
|
119
114
|
|
|
120
115
|
consumer_handler.on_delivery do |delivery_info, metadata, payload|
|
|
121
116
|
consumer_handler.process_delivery(delivery_info, metadata, payload)
|
|
@@ -126,6 +121,12 @@ module Lepus
|
|
|
126
121
|
end
|
|
127
122
|
end
|
|
128
123
|
|
|
124
|
+
# Factory method for creating consumer handlers.
|
|
125
|
+
# Overridden by Lepus::Web to attach stats tracking.
|
|
126
|
+
def build_handler(consumer_class, channel, queue, tag)
|
|
127
|
+
Lepus::Consumers::Handler.new(consumer_class, channel, queue, tag)
|
|
128
|
+
end
|
|
129
|
+
|
|
129
130
|
def connection_pool
|
|
130
131
|
return @connection_pool if defined?(@connection_pool)
|
|
131
132
|
|
data/lib/lepus/process.rb
CHANGED
|
@@ -74,12 +74,12 @@ module Lepus
|
|
|
74
74
|
Processes::MEMORY_GRABBER.call(pid)
|
|
75
75
|
end
|
|
76
76
|
|
|
77
|
-
def heartbeat
|
|
77
|
+
def heartbeat(metrics: {})
|
|
78
78
|
now = Time.now
|
|
79
79
|
Lepus.instrument :heartbeat_process, process: self, rss_memory: 0, last_heartbeat_at: now do |payload|
|
|
80
80
|
ProcessRegistry.find(id) # ensure process is still registered
|
|
81
81
|
|
|
82
|
-
update_attributes(last_heartbeat_at: now)
|
|
82
|
+
update_attributes(last_heartbeat_at: now, metrics: metrics)
|
|
83
83
|
payload[:rss_memory] = rss_memory
|
|
84
84
|
rescue Exception => error # rubocop:disable Lint/RescueException
|
|
85
85
|
payload[:error] = error
|
|
@@ -87,9 +87,9 @@ module Lepus
|
|
|
87
87
|
end
|
|
88
88
|
end
|
|
89
89
|
|
|
90
|
-
def update_attributes(new_attributes)
|
|
90
|
+
def update_attributes(metrics: {}, **new_attributes)
|
|
91
91
|
@attributes = @attributes.merge(new_attributes)
|
|
92
|
-
ProcessRegistry.update(self)
|
|
92
|
+
ProcessRegistry.update(self, metrics: metrics)
|
|
93
93
|
end
|
|
94
94
|
|
|
95
95
|
def destroy!
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Lepus
|
|
4
|
+
class ProcessRegistry
|
|
5
|
+
# Abstract backend interface for process registry storage.
|
|
6
|
+
# Implementations must provide all methods defined here.
|
|
7
|
+
module Backend
|
|
8
|
+
def start
|
|
9
|
+
raise NotImplementedError, "#{self.class}#start must be implemented"
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def stop
|
|
13
|
+
raise NotImplementedError, "#{self.class}#stop must be implemented"
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def add(process)
|
|
17
|
+
raise NotImplementedError, "#{self.class}#add must be implemented"
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def update(process, metrics: {})
|
|
21
|
+
add(process, metrics: metrics)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def delete(process)
|
|
25
|
+
raise NotImplementedError, "#{self.class}#delete must be implemented"
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def find(id)
|
|
29
|
+
raise NotImplementedError, "#{self.class}#find must be implemented"
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def exists?(id)
|
|
33
|
+
raise NotImplementedError, "#{self.class}#exists? must be implemented"
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def all
|
|
37
|
+
raise NotImplementedError, "#{self.class}#all must be implemented"
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def count
|
|
41
|
+
raise NotImplementedError, "#{self.class}#count must be implemented"
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def clear
|
|
45
|
+
raise NotImplementedError, "#{self.class}#clear must be implemented"
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|