lepus 0.0.1.beta2 → 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.
Files changed (125) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/linter.yml +21 -0
  3. data/.github/workflows/specs.yml +93 -13
  4. data/.gitignore +2 -0
  5. data/.rubocop.yml +10 -0
  6. data/.tool-versions +1 -1
  7. data/Gemfile +7 -0
  8. data/Gemfile.lock +36 -9
  9. data/Makefile +19 -0
  10. data/README.md +562 -7
  11. data/bin/setup +5 -2
  12. data/config.ru +14 -0
  13. data/docker-compose.yml +5 -3
  14. data/docs/README.md +80 -0
  15. data/docs/cli.md +108 -0
  16. data/docs/configuration.md +171 -0
  17. data/docs/consumers.md +168 -0
  18. data/docs/getting-started.md +136 -0
  19. data/docs/images/lepus-web.png +0 -0
  20. data/docs/middleware.md +240 -0
  21. data/docs/producers.md +173 -0
  22. data/docs/prometheus.md +112 -0
  23. data/docs/rails.md +161 -0
  24. data/docs/supervisor.md +112 -0
  25. data/docs/testing.md +141 -0
  26. data/docs/web.md +85 -0
  27. data/examples/grafana-dashboard.json +450 -0
  28. data/gemfiles/Gemfile.rails-5.2 +7 -0
  29. data/gemfiles/{rails52.gemfile.lock → Gemfile.rails-5.2.lock} +102 -69
  30. data/gemfiles/Gemfile.rails-6.1 +7 -0
  31. data/gemfiles/{rails61.gemfile.lock → Gemfile.rails-6.1.lock} +113 -79
  32. data/gemfiles/{rails52.gemfile → Gemfile.rails-7.2} +1 -1
  33. data/gemfiles/Gemfile.rails-7.2.lock +321 -0
  34. data/gemfiles/{rails61.gemfile → Gemfile.rails-8.0} +1 -1
  35. data/gemfiles/Gemfile.rails-8.0.lock +322 -0
  36. data/lepus.gemspec +7 -1
  37. data/lib/lepus/cli.rb +35 -4
  38. data/lib/lepus/configuration.rb +107 -0
  39. data/lib/lepus/connection_pool.rb +135 -0
  40. data/lib/lepus/consumer.rb +59 -41
  41. data/lib/lepus/consumers/config.rb +183 -0
  42. data/lib/lepus/consumers/handler.rb +56 -0
  43. data/lib/lepus/consumers/middleware_chain.rb +22 -0
  44. data/lib/lepus/consumers/middlewares/exception_logger.rb +27 -0
  45. data/lib/lepus/consumers/middlewares/honeybadger.rb +33 -0
  46. data/lib/lepus/consumers/middlewares/json.rb +37 -0
  47. data/lib/lepus/consumers/middlewares/max_retry.rb +83 -0
  48. data/lib/lepus/consumers/middlewares/unique.rb +65 -0
  49. data/lib/lepus/consumers/stats.rb +70 -0
  50. data/lib/lepus/consumers/stats_registry.rb +29 -0
  51. data/lib/lepus/consumers/worker.rb +141 -0
  52. data/lib/lepus/consumers/worker_factory.rb +124 -0
  53. data/lib/lepus/consumers.rb +6 -0
  54. data/lib/lepus/message/delivery_info.rb +72 -0
  55. data/lib/lepus/message/metadata.rb +99 -0
  56. data/lib/lepus/message.rb +88 -5
  57. data/lib/lepus/middleware_chain.rb +83 -0
  58. data/lib/lepus/primitive/hash.rb +29 -0
  59. data/lib/lepus/process.rb +24 -24
  60. data/lib/lepus/process_registry/backend.rb +49 -0
  61. data/lib/lepus/process_registry/file_backend.rb +108 -0
  62. data/lib/lepus/process_registry/message_builder.rb +72 -0
  63. data/lib/lepus/process_registry/rabbitmq_backend.rb +153 -0
  64. data/lib/lepus/process_registry.rb +56 -23
  65. data/lib/lepus/processes/base.rb +0 -5
  66. data/lib/lepus/processes/callbacks.rb +3 -0
  67. data/lib/lepus/processes/interruptible.rb +4 -8
  68. data/lib/lepus/processes/procline.rb +1 -1
  69. data/lib/lepus/processes/registrable.rb +1 -1
  70. data/lib/lepus/processes/runnable.rb +1 -1
  71. data/lib/lepus/processes.rb +15 -0
  72. data/lib/lepus/producer.rb +141 -30
  73. data/lib/lepus/producers/config.rb +46 -0
  74. data/lib/lepus/producers/definition.rb +48 -0
  75. data/lib/lepus/producers/hooks.rb +170 -0
  76. data/lib/lepus/producers/middleware_chain.rb +22 -0
  77. data/lib/lepus/producers/middlewares/correlation_id.rb +37 -0
  78. data/lib/lepus/producers/middlewares/header.rb +47 -0
  79. data/lib/lepus/producers/middlewares/instrumentation.rb +30 -0
  80. data/lib/lepus/producers/middlewares/json.rb +47 -0
  81. data/lib/lepus/producers/middlewares/unique.rb +67 -0
  82. data/lib/lepus/producers.rb +7 -0
  83. data/lib/lepus/prometheus/collector.rb +149 -0
  84. data/lib/lepus/prometheus/instrumentation.rb +168 -0
  85. data/lib/lepus/prometheus.rb +48 -0
  86. data/lib/lepus/publisher.rb +67 -0
  87. data/lib/lepus/supervisor/children_pipes.rb +25 -0
  88. data/lib/lepus/supervisor/lifecycle_hooks.rb +50 -0
  89. data/lib/lepus/supervisor/pidfiled.rb +1 -1
  90. data/lib/lepus/supervisor/registry_cleaner.rb +22 -0
  91. data/lib/lepus/supervisor.rb +129 -25
  92. data/lib/lepus/testing/exchange.rb +95 -0
  93. data/lib/lepus/testing/message_builder.rb +177 -0
  94. data/lib/lepus/testing/rspec_matchers.rb +258 -0
  95. data/lib/lepus/testing.rb +210 -0
  96. data/lib/lepus/unique.rb +18 -0
  97. data/lib/lepus/version.rb +1 -1
  98. data/lib/lepus/web/aggregator.rb +154 -0
  99. data/lib/lepus/web/api.rb +132 -0
  100. data/lib/lepus/web/app.rb +37 -0
  101. data/lib/lepus/web/management_api.rb +192 -0
  102. data/lib/lepus/web/respond_with.rb +28 -0
  103. data/lib/lepus/web.rb +238 -0
  104. data/lib/lepus.rb +39 -28
  105. data/test_offline.html +189 -0
  106. data/web/assets/css/styles.css +635 -0
  107. data/web/assets/js/app.js +6 -0
  108. data/web/assets/js/bootstrap.js +20 -0
  109. data/web/assets/js/controllers/connection_controller.js +44 -0
  110. data/web/assets/js/controllers/dashboard_controller.js +499 -0
  111. data/web/assets/js/controllers/queue_controller.js +17 -0
  112. data/web/assets/js/controllers/theme_controller.js +31 -0
  113. data/web/assets/js/offline-manager.js +233 -0
  114. data/web/assets/js/service-worker-manager.js +65 -0
  115. data/web/index.html +159 -0
  116. data/web/sw.js +144 -0
  117. metadata +177 -18
  118. data/lib/lepus/consumer_config.rb +0 -149
  119. data/lib/lepus/consumer_wrapper.rb +0 -46
  120. data/lib/lepus/lifecycle_hooks.rb +0 -49
  121. data/lib/lepus/middlewares/honeybadger.rb +0 -23
  122. data/lib/lepus/middlewares/json.rb +0 -35
  123. data/lib/lepus/middlewares/max_retry.rb +0 -57
  124. data/lib/lepus/processes/consumer.rb +0 -113
  125. data/lib/lepus/supervisor/config.rb +0 -45
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lepus
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1.beta2
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Marcos G. Zimmermann
8
8
  autorequire:
9
9
  bindir: exec
10
10
  cert_chain: []
11
- date: 2025-02-11 00:00:00.000000000 Z
11
+ date: 2026-04-27 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: base64
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 0.0.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 0.0.0
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: bunny
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -108,6 +122,34 @@ dependencies:
108
122
  - - ">="
109
123
  - !ruby/object:Gem::Version
110
124
  version: '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: '2.2'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '2.2'
139
+ - !ruby/object:Gem::Dependency
140
+ name: rack-test
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
111
153
  - !ruby/object:Gem::Dependency
112
154
  name: rspec
113
155
  requirement: !ruby/object:Gem::Requirement
@@ -192,7 +234,49 @@ dependencies:
192
234
  - - ">="
193
235
  - !ruby/object:Gem::Version
194
236
  version: '0'
195
- description: 'RabbitMQ consumers/producer for ruby applicationsd
237
+ - !ruby/object:Gem::Dependency
238
+ name: simplecov
239
+ requirement: !ruby/object:Gem::Requirement
240
+ requirements:
241
+ - - ">="
242
+ - !ruby/object:Gem::Version
243
+ version: '0'
244
+ type: :development
245
+ prerelease: false
246
+ version_requirements: !ruby/object:Gem::Requirement
247
+ requirements:
248
+ - - ">="
249
+ - !ruby/object:Gem::Version
250
+ version: '0'
251
+ - !ruby/object:Gem::Dependency
252
+ name: de-dupe
253
+ requirement: !ruby/object:Gem::Requirement
254
+ requirements:
255
+ - - ">="
256
+ - !ruby/object:Gem::Version
257
+ version: '0'
258
+ type: :development
259
+ prerelease: false
260
+ version_requirements: !ruby/object:Gem::Requirement
261
+ requirements:
262
+ - - ">="
263
+ - !ruby/object:Gem::Version
264
+ version: '0'
265
+ - !ruby/object:Gem::Dependency
266
+ name: prometheus_exporter
267
+ requirement: !ruby/object:Gem::Requirement
268
+ requirements:
269
+ - - ">="
270
+ - !ruby/object:Gem::Version
271
+ version: '0'
272
+ type: :development
273
+ prerelease: false
274
+ version_requirements: !ruby/object:Gem::Requirement
275
+ requirements:
276
+ - - ">="
277
+ - !ruby/object:Gem::Version
278
+ version: '0'
279
+ description: 'RabbitMQ consumers/producer for ruby applications
196
280
 
197
281
  '
198
282
  email:
@@ -202,6 +286,7 @@ executables:
202
286
  extensions: []
203
287
  extra_rdoc_files: []
204
288
  files:
289
+ - ".github/workflows/linter.yml"
205
290
  - ".github/workflows/specs.yml"
206
291
  - ".gitignore"
207
292
  - ".rspec"
@@ -211,55 +296,129 @@ files:
211
296
  - Gemfile
212
297
  - Gemfile.lock
213
298
  - LICENSE.txt
299
+ - Makefile
214
300
  - README.md
215
301
  - Rakefile
216
302
  - bin/console
217
303
  - bin/setup
304
+ - config.ru
218
305
  - docker-compose.yml
306
+ - docs/README.md
307
+ - docs/cli.md
308
+ - docs/configuration.md
309
+ - docs/consumers.md
310
+ - docs/getting-started.md
311
+ - docs/images/lepus-web.png
312
+ - docs/middleware.md
313
+ - docs/producers.md
314
+ - docs/prometheus.md
315
+ - docs/rails.md
316
+ - docs/supervisor.md
317
+ - docs/testing.md
318
+ - docs/web.md
319
+ - examples/grafana-dashboard.json
219
320
  - exec/lepus
220
- - gemfiles/rails52.gemfile
221
- - gemfiles/rails52.gemfile.lock
222
- - gemfiles/rails61.gemfile
223
- - gemfiles/rails61.gemfile.lock
321
+ - gemfiles/Gemfile.rails-5.2
322
+ - gemfiles/Gemfile.rails-5.2.lock
323
+ - gemfiles/Gemfile.rails-6.1
324
+ - gemfiles/Gemfile.rails-6.1.lock
325
+ - gemfiles/Gemfile.rails-7.2
326
+ - gemfiles/Gemfile.rails-7.2.lock
327
+ - gemfiles/Gemfile.rails-8.0
328
+ - gemfiles/Gemfile.rails-8.0.lock
224
329
  - lepus.gemspec
225
330
  - lib/lepus.rb
226
331
  - lib/lepus/app_executor.rb
227
332
  - lib/lepus/cli.rb
228
333
  - lib/lepus/configuration.rb
334
+ - lib/lepus/connection_pool.rb
229
335
  - lib/lepus/consumer.rb
230
- - lib/lepus/consumer_config.rb
231
- - lib/lepus/consumer_wrapper.rb
232
- - lib/lepus/lifecycle_hooks.rb
336
+ - lib/lepus/consumers.rb
337
+ - lib/lepus/consumers/config.rb
338
+ - lib/lepus/consumers/handler.rb
339
+ - lib/lepus/consumers/middleware_chain.rb
340
+ - lib/lepus/consumers/middlewares/exception_logger.rb
341
+ - lib/lepus/consumers/middlewares/honeybadger.rb
342
+ - lib/lepus/consumers/middlewares/json.rb
343
+ - lib/lepus/consumers/middlewares/max_retry.rb
344
+ - lib/lepus/consumers/middlewares/unique.rb
345
+ - lib/lepus/consumers/stats.rb
346
+ - lib/lepus/consumers/stats_registry.rb
347
+ - lib/lepus/consumers/worker.rb
348
+ - lib/lepus/consumers/worker_factory.rb
233
349
  - lib/lepus/message.rb
350
+ - lib/lepus/message/delivery_info.rb
351
+ - lib/lepus/message/metadata.rb
234
352
  - lib/lepus/middleware.rb
235
- - lib/lepus/middlewares/honeybadger.rb
236
- - lib/lepus/middlewares/json.rb
237
- - lib/lepus/middlewares/max_retry.rb
353
+ - lib/lepus/middleware_chain.rb
354
+ - lib/lepus/primitive/hash.rb
238
355
  - lib/lepus/primitive/string.rb
239
356
  - lib/lepus/process.rb
240
357
  - lib/lepus/process_registry.rb
358
+ - lib/lepus/process_registry/backend.rb
359
+ - lib/lepus/process_registry/file_backend.rb
360
+ - lib/lepus/process_registry/message_builder.rb
361
+ - lib/lepus/process_registry/rabbitmq_backend.rb
241
362
  - lib/lepus/processes.rb
242
363
  - lib/lepus/processes/base.rb
243
364
  - lib/lepus/processes/callbacks.rb
244
- - lib/lepus/processes/consumer.rb
245
365
  - lib/lepus/processes/interruptible.rb
246
366
  - lib/lepus/processes/procline.rb
247
367
  - lib/lepus/processes/registrable.rb
248
368
  - lib/lepus/processes/runnable.rb
249
369
  - lib/lepus/processes/supervised.rb
250
370
  - lib/lepus/producer.rb
371
+ - lib/lepus/producers.rb
372
+ - lib/lepus/producers/config.rb
373
+ - lib/lepus/producers/definition.rb
374
+ - lib/lepus/producers/hooks.rb
375
+ - lib/lepus/producers/middleware_chain.rb
376
+ - lib/lepus/producers/middlewares/correlation_id.rb
377
+ - lib/lepus/producers/middlewares/header.rb
378
+ - lib/lepus/producers/middlewares/instrumentation.rb
379
+ - lib/lepus/producers/middlewares/json.rb
380
+ - lib/lepus/producers/middlewares/unique.rb
381
+ - lib/lepus/prometheus.rb
382
+ - lib/lepus/prometheus/collector.rb
383
+ - lib/lepus/prometheus/instrumentation.rb
384
+ - lib/lepus/publisher.rb
251
385
  - lib/lepus/rails.rb
252
386
  - lib/lepus/rails/log_subscriber.rb
253
387
  - lib/lepus/rails/railtie.rb
254
388
  - lib/lepus/supervisor.rb
255
- - lib/lepus/supervisor/config.rb
389
+ - lib/lepus/supervisor/children_pipes.rb
390
+ - lib/lepus/supervisor/lifecycle_hooks.rb
256
391
  - lib/lepus/supervisor/maintenance.rb
257
392
  - lib/lepus/supervisor/pidfile.rb
258
393
  - lib/lepus/supervisor/pidfiled.rb
394
+ - lib/lepus/supervisor/registry_cleaner.rb
259
395
  - lib/lepus/supervisor/signals.rb
396
+ - lib/lepus/testing.rb
397
+ - lib/lepus/testing/exchange.rb
398
+ - lib/lepus/testing/message_builder.rb
399
+ - lib/lepus/testing/rspec_matchers.rb
260
400
  - lib/lepus/timer.rb
401
+ - lib/lepus/unique.rb
261
402
  - lib/lepus/version.rb
403
+ - lib/lepus/web.rb
404
+ - lib/lepus/web/aggregator.rb
405
+ - lib/lepus/web/api.rb
406
+ - lib/lepus/web/app.rb
407
+ - lib/lepus/web/management_api.rb
408
+ - lib/lepus/web/respond_with.rb
262
409
  - lib/puma/plugin/lepus.rb
410
+ - test_offline.html
411
+ - web/assets/css/styles.css
412
+ - web/assets/js/app.js
413
+ - web/assets/js/bootstrap.js
414
+ - web/assets/js/controllers/connection_controller.js
415
+ - web/assets/js/controllers/dashboard_controller.js
416
+ - web/assets/js/controllers/queue_controller.js
417
+ - web/assets/js/controllers/theme_controller.js
418
+ - web/assets/js/offline-manager.js
419
+ - web/assets/js/service-worker-manager.js
420
+ - web/index.html
421
+ - web/sw.js
263
422
  homepage: https://github.com/marcosgz/lepus
264
423
  licenses:
265
424
  - MIT
@@ -279,11 +438,11 @@ required_ruby_version: !ruby/object:Gem::Requirement
279
438
  version: 2.7.0
280
439
  required_rubygems_version: !ruby/object:Gem::Requirement
281
440
  requirements:
282
- - - ">"
441
+ - - ">="
283
442
  - !ruby/object:Gem::Version
284
- version: 1.3.1
443
+ version: '0'
285
444
  requirements: []
286
- rubygems_version: 3.1.6
445
+ rubygems_version: 3.4.10
287
446
  signing_key:
288
447
  specification_version: 4
289
448
  summary: RabbitMQ consumers/producer for ruby applications
@@ -1,149 +0,0 @@
1
- require "bunny"
2
-
3
- module Lepus
4
- # Parse the list of options for the consumer.
5
- class ConsumerConfig
6
- DEFAULT_EXCHANGE_OPTIONS = {
7
- name: nil,
8
- type: :topic, # The type of the exchange (:direct, :fanout, :topic or :headers).
9
- durable: true
10
- }.freeze
11
-
12
- DEFAULT_QUEUE_OPTIONS = {
13
- name: nil,
14
- durable: true
15
- }.freeze
16
-
17
- DEFAULT_RETRY_QUEUE_OPTIONS = {
18
- name: nil,
19
- durable: true,
20
- delay: 5000,
21
- arguments: {}
22
- }
23
-
24
- DEFAULT_ERROR_QUEUE_OPTIONS = DEFAULT_QUEUE_OPTIONS
25
-
26
- attr_reader :options
27
-
28
- def initialize(options = {})
29
- opts = HashUtil.deep_symbolize_keys(options)
30
-
31
- @exchange_opts = DEFAULT_EXCHANGE_OPTIONS.merge(
32
- declaration_config(opts.delete(:exchange))
33
- )
34
- @queue_opts = DEFAULT_QUEUE_OPTIONS.merge(
35
- declaration_config(opts.delete(:queue))
36
- )
37
- if (value = opts.delete(:retry_queue))
38
- @retry_queue_opts = DEFAULT_RETRY_QUEUE_OPTIONS.merge(
39
- declaration_config(value)
40
- )
41
- end
42
- if (value = opts.delete(:error_queue))
43
- @error_queue_opts = DEFAULT_ERROR_QUEUE_OPTIONS.merge(
44
- declaration_config(value)
45
- )
46
- end
47
- @bind_opts = opts.delete(:bind) || {}
48
- if (routing_key = opts.delete(:routing_key))
49
- @bind_opts[:routing_key] ||= routing_key
50
- end
51
- @options = opts
52
- end
53
-
54
- def channel_args
55
- @channel_opts.values_at(
56
- :consumer_pool_size,
57
- :consumer_pool_abort_on_exception,
58
- :consumer_pool_shutdown_timeout
59
- )
60
- end
61
-
62
- def exchange_args
63
- [exchange_name, @exchange_opts.reject { |k, v| k == :name }]
64
- end
65
-
66
- def consumer_queue_args
67
- opts = @queue_opts.reject { |k, v| k == :name }
68
- return [queue_name, opts] unless retry_queue_args
69
-
70
- opts[:arguments] ||= {}
71
- opts[:arguments]["x-dead-letter-exchange"] = ""
72
- opts[:arguments]["x-dead-letter-routing-key"] = retry_queue_name
73
-
74
- [queue_name, opts]
75
- end
76
-
77
- def retry_queue_args
78
- return unless @retry_queue_opts
79
-
80
- delay = @retry_queue_opts[:delay]
81
- args = (@retry_queue_opts[:arguments] || {}).merge(
82
- "x-dead-letter-exchange" => "",
83
- "x-dead-letter-routing-key" => queue_name,
84
- "x-message-ttl" => delay
85
- )
86
- extra_keys = %i[name delay]
87
- opts = @retry_queue_opts.reject { |k, v| extra_keys.include?(k) }
88
- [retry_queue_name, opts.merge(arguments: args)]
89
- end
90
-
91
- def error_queue_args
92
- return unless @error_queue_opts
93
-
94
- name = @error_queue_opts[:name]
95
- name ||= "#{queue_name}.error"
96
- [name, @error_queue_opts.reject { |k, v| k == :name }]
97
- end
98
-
99
- def binds_args
100
- arguments = @bind_opts.fetch(:arguments, {}).transform_keys(&:to_s)
101
- opts = {}
102
- opts[:arguments] = arguments unless arguments.empty?
103
- if (routing_keys = @bind_opts[:routing_key]).is_a?(Array)
104
- routing_keys.map { |key| opts.merge(routing_key: key) }
105
- elsif (routing_key = @bind_opts[:routing_key])
106
- [opts.merge(routing_key: routing_key)]
107
- else
108
- [opts]
109
- end
110
- end
111
-
112
- protected
113
-
114
- def exchange_name
115
- @exchange_opts[:name] || raise(InvalidConsumerConfigError, "Exchange name is required")
116
- end
117
-
118
- def queue_name
119
- @queue_opts[:name] || raise(InvalidConsumerConfigError, "Queue name is required")
120
- end
121
-
122
- def retry_queue_name
123
- name = @retry_queue_opts[:name]
124
- name ||= "#{queue_name}.retry"
125
- name
126
- end
127
-
128
- # Normalizes a declaration config (for exchanges and queues) into a configuration Hash.
129
- #
130
- # If the given `value` is a String, convert it to a Hash with the key `:name` and the value.
131
- # If the given `value` is a Hash, leave it as is.
132
- def declaration_config(value)
133
- case value
134
- when Hash then value
135
- when String then {name: value}
136
- when NilClass then {}
137
- when TrueClass then {}
138
- end
139
- end
140
-
141
- class HashUtil
142
- def self.deep_symbolize_keys(hash)
143
- hash.each_with_object({}) do |(k, v), memo|
144
- memo[k.to_sym] = v.is_a?(Hash) ? deep_symbolize_keys(v) : v
145
- end
146
- end
147
- end
148
- end
149
- end
@@ -1,46 +0,0 @@
1
- require "bunny"
2
-
3
- module Lepus
4
- # Wraps the user-defined consumer to provide the expected interface to Bunny.
5
- class ConsumerWrapper < Bunny::Consumer
6
- # @param [Lepus::Consumer] consumer The user-defined consumer implementation derived from {Lepus::Consumer}.
7
- # @param [Bunny::Channel] channel The channel used for the consumer.
8
- # @param [Bunny::Queue] queue The queue the consumer is subscribed to.
9
- # @param [String] consumer_tag A string identifying the consumer instance.
10
- # @param [Hash] arguments Arguments that are passed on to +Bunny::Consumer.new+.
11
- def initialize(consumer, channel, queue, consumer_tag, arguments = {})
12
- @consumer = consumer
13
- super(channel, queue, consumer_tag, false, false, arguments)
14
- end
15
-
16
- # Called when a message is received from the subscribed queue.
17
- #
18
- # @param [Bunny::DeliveryInfo] delivery_info The delivery info of the received message.
19
- # @param [Bunny::MessageProperties] metadata The metadata of the received message.
20
- # @param [String] payload The payload of the received message.
21
- def process_delivery(delivery_info, metadata, payload)
22
- consumer
23
- .process_delivery(delivery_info, metadata, payload)
24
- .tap { |result| process_result(result, delivery_info.delivery_tag) }
25
- end
26
-
27
- private
28
-
29
- attr_reader :consumer
30
-
31
- def process_result(result, delivery_tag)
32
- case result
33
- when :ack
34
- channel.ack(delivery_tag, false)
35
- when :reject
36
- channel.reject(delivery_tag)
37
- when :requeue
38
- channel.reject(delivery_tag, true)
39
- when :nack
40
- channel.nack(delivery_tag, false, true)
41
- else
42
- raise Lepus::InvalidConsumerReturnError, result
43
- end
44
- end
45
- end
46
- end
@@ -1,49 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Lepus
4
- # @TODO: Move after/before fork hooks to this module
5
- module LifecycleHooks
6
- def self.included(base)
7
- base.extend ClassMethods
8
- base.send :include, InstanceMethods
9
- base.instance_variable_set(:@lifecycle_hooks, {start: [], stop: []})
10
- end
11
-
12
- module ClassMethods
13
- attr_reader :lifecycle_hooks
14
-
15
- def on_start(&block)
16
- lifecycle_hooks[:start] << block
17
- end
18
-
19
- def on_stop(&block)
20
- lifecycle_hooks[:stop] << block
21
- end
22
-
23
- def clear_hooks
24
- lifecycle_hooks[:start] = []
25
- lifecycle_hooks[:stop] = []
26
- end
27
- end
28
-
29
- module InstanceMethods
30
- private
31
-
32
- def run_start_hooks
33
- run_hooks_for :start
34
- end
35
-
36
- def run_stop_hooks
37
- run_hooks_for :stop
38
- end
39
-
40
- def run_hooks_for(event)
41
- self.class.lifecycle_hooks.fetch(event, []).each do |block|
42
- block.call
43
- rescue Exception => exception # rubocop:disable Lint/RescueException
44
- handle_thread_error(exception)
45
- end
46
- end
47
- end
48
- end
49
- end
@@ -1,23 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Lepus
4
- module Middlewares
5
- # A middleware that automatically wraps {Lepus::Consumer#perform]} in an Honeybadger transaction.
6
- class Honeybadger < Lepus::Middleware
7
- # @param [Hash] opts The options for the middleware.
8
- # @option opts [String] :class_name The name of the class you want to monitor.
9
- def initialize(class_name:, **)
10
- super
11
-
12
- @class_name = class_name
13
- end
14
-
15
- def call(message, app)
16
- app.call(message)
17
- rescue => err
18
- ::Honeybadger.notify(err, context: {class_name: @class_name})
19
- raise err
20
- end
21
- end
22
- end
23
- end
@@ -1,35 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "multi_json"
4
-
5
- module Lepus
6
- module Middlewares
7
- # A middleware that automatically parses your JSON payload.
8
- class JSON < Lepus::Middleware
9
- # @param [Hash] opts The options for the middleware.
10
- # @option opts [Proc] :on_error (Proc.new { :reject }) A Proc to be called when an error occurs during processing.
11
- # @option opts [Boolean] :symbolize_keys (false) Whether to symbolize the keys of your payload.
12
- def initialize(**opts)
13
- super
14
-
15
- @on_error = opts.fetch(:on_error, proc { :reject })
16
- @symbolize_keys = opts.fetch(:symbolize_keys, false)
17
- end
18
-
19
- def call(message, app)
20
- begin
21
- parsed_payload =
22
- MultiJson.load(message.payload, symbolize_keys: symbolize_keys)
23
- rescue => e
24
- return on_error.call(e)
25
- end
26
-
27
- app.call(message.mutate(payload: parsed_payload))
28
- end
29
-
30
- private
31
-
32
- attr_reader :symbolize_keys, :on_error
33
- end
34
- end
35
- end
@@ -1,57 +0,0 @@
1
- module Lepus
2
- module Middlewares
3
- # A middleware that automatically puts messages on an error queue when the specified number of retries are exceeded.
4
- class MaxRetry < Lepus::Middleware
5
- include Lepus::AppExecutor
6
-
7
- # @param [Hash] opts The options for the middleware.
8
- # @option opts [Integer] :retries The number of retries before the message is sent to the error queue.
9
- # @option opts [String] :error_queue The name of the queue where messages should be sent to when the max retries are reached.
10
- def initialize(retries:, error_queue:)
11
- super
12
-
13
- @retries = retries
14
- @error_queue = error_queue
15
- end
16
-
17
- def call(message, app)
18
- return handle_exceeded(message) if retries_exceeded?(message.metadata)
19
-
20
- app.call(message)
21
- end
22
-
23
- private
24
-
25
- attr_reader :retries, :error_queue
26
-
27
- def handle_exceeded(message)
28
- payload = message.payload
29
- payload = MultiJson.dump(payload) if payload.is_a?(Hash)
30
- ::Bunny::Exchange.default(message.delivery_info.channel).publish(
31
- payload,
32
- routing_key: error_queue
33
- )
34
- :ack
35
- rescue => err
36
- handle_thread_error(err)
37
- end
38
-
39
- def retries_exceeded?(metadata)
40
- return false if metadata.headers.nil?
41
-
42
- rejected_deaths =
43
- metadata
44
- .headers
45
- .fetch("x-death", [])
46
- .select { |death| death["reason"] == "rejected" }
47
-
48
- return false unless rejected_deaths.any?
49
-
50
- retry_count = rejected_deaths.map { |death| death["count"] }.compact.max
51
- return false unless retry_count
52
-
53
- retry_count > @retries
54
- end
55
- end
56
- end
57
- end