lepus 0.0.1.beta2

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 (60) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/specs.yml +44 -0
  3. data/.gitignore +12 -0
  4. data/.rspec +1 -0
  5. data/.rubocop.yml +35 -0
  6. data/.tool-versions +1 -0
  7. data/CHANGELOG.md +10 -0
  8. data/Gemfile +6 -0
  9. data/Gemfile.lock +120 -0
  10. data/LICENSE.txt +21 -0
  11. data/README.md +213 -0
  12. data/Rakefile +4 -0
  13. data/bin/console +9 -0
  14. data/bin/setup +7 -0
  15. data/docker-compose.yml +8 -0
  16. data/exec/lepus +9 -0
  17. data/gemfiles/rails52.gemfile +5 -0
  18. data/gemfiles/rails52.gemfile.lock +242 -0
  19. data/gemfiles/rails61.gemfile +5 -0
  20. data/gemfiles/rails61.gemfile.lock +260 -0
  21. data/lepus.gemspec +53 -0
  22. data/lib/lepus/app_executor.rb +19 -0
  23. data/lib/lepus/cli.rb +27 -0
  24. data/lib/lepus/configuration.rb +90 -0
  25. data/lib/lepus/consumer.rb +177 -0
  26. data/lib/lepus/consumer_config.rb +149 -0
  27. data/lib/lepus/consumer_wrapper.rb +46 -0
  28. data/lib/lepus/lifecycle_hooks.rb +49 -0
  29. data/lib/lepus/message.rb +37 -0
  30. data/lib/lepus/middleware.rb +18 -0
  31. data/lib/lepus/middlewares/honeybadger.rb +23 -0
  32. data/lib/lepus/middlewares/json.rb +35 -0
  33. data/lib/lepus/middlewares/max_retry.rb +57 -0
  34. data/lib/lepus/primitive/string.rb +55 -0
  35. data/lib/lepus/process.rb +136 -0
  36. data/lib/lepus/process_registry.rb +37 -0
  37. data/lib/lepus/processes/base.rb +50 -0
  38. data/lib/lepus/processes/callbacks.rb +72 -0
  39. data/lib/lepus/processes/consumer.rb +113 -0
  40. data/lib/lepus/processes/interruptible.rb +38 -0
  41. data/lib/lepus/processes/procline.rb +11 -0
  42. data/lib/lepus/processes/registrable.rb +67 -0
  43. data/lib/lepus/processes/runnable.rb +102 -0
  44. data/lib/lepus/processes/supervised.rb +44 -0
  45. data/lib/lepus/processes.rb +6 -0
  46. data/lib/lepus/producer.rb +42 -0
  47. data/lib/lepus/rails/log_subscriber.rb +120 -0
  48. data/lib/lepus/rails/railtie.rb +31 -0
  49. data/lib/lepus/rails.rb +7 -0
  50. data/lib/lepus/supervisor/config.rb +45 -0
  51. data/lib/lepus/supervisor/maintenance.rb +35 -0
  52. data/lib/lepus/supervisor/pidfile.rb +61 -0
  53. data/lib/lepus/supervisor/pidfiled.rb +29 -0
  54. data/lib/lepus/supervisor/signals.rb +71 -0
  55. data/lib/lepus/supervisor.rb +204 -0
  56. data/lib/lepus/timer.rb +29 -0
  57. data/lib/lepus/version.rb +5 -0
  58. data/lib/lepus.rb +95 -0
  59. data/lib/puma/plugin/lepus.rb +74 -0
  60. metadata +290 -0
data/lib/lepus.rb ADDED
@@ -0,0 +1,95 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bunny"
4
+ require "concurrent"
5
+ require "fileutils"
6
+ require "logger"
7
+ require "pathname"
8
+ require "securerandom"
9
+ require "singleton"
10
+ require "socket"
11
+ require "time"
12
+ require "yaml"
13
+ require "zeitwerk"
14
+
15
+ loader = Zeitwerk::Loader.for_gem(warn_on_extra_files: false)
16
+ loader.inflector.inflect "json" => "JSON"
17
+ loader.inflector.inflect "cli" => "CLI"
18
+ loader.collapse("#{__dir__}/lepus/rails.rb")
19
+ loader.collapse("#{__dir__}/lepus/rails/*")
20
+ loader.ignore("#{__dir__}/puma")
21
+ loader.ignore("#{__dir__}/lepus/rails")
22
+ loader.ignore("#{__dir__}/lepus/rails.rb")
23
+ loader.ignore("#{__dir__}/lepus/cli.rb")
24
+ loader.ignore("#{__dir__}/lepus/middlewares")
25
+ loader.log! if ENV["DEBUG"]
26
+ loader.setup
27
+
28
+ module Lepus
29
+ DEFAULT_LOGGER = Logger.new($stdout)
30
+
31
+ class Error < StandardError
32
+ end
33
+
34
+ # Error that is raised when an invalid value is returned from {#work}
35
+ class InvalidConsumerReturnError < Error
36
+ def initialize(value)
37
+ super(
38
+ "#perform must return :ack, :reject or :requeue, received #{value.inspect} instead",
39
+ )
40
+ end
41
+ end
42
+
43
+ class InvalidConsumerConfigError < Error
44
+ end
45
+
46
+ class ShutdownError < Error
47
+ end
48
+
49
+ # Error that is raised when the Bunny recovery attempts are exhausted.
50
+ class MaxRecoveryAttemptsExhaustedError < ShutdownError
51
+ end
52
+
53
+ extend self
54
+
55
+ def logger
56
+ @logger ||= DEFAULT_LOGGER
57
+ end
58
+
59
+ def logger=(logger)
60
+ @logger = logger
61
+ end
62
+
63
+ def instrument(channel, **options, &block)
64
+ if defined?(ActiveSupport::Notifications)
65
+ ActiveSupport::Notifications.instrument("#{channel}.lepus", **options, &block)
66
+ else
67
+ yield(options.dup)
68
+ end
69
+ end
70
+
71
+ def eager_load_consumers!
72
+ return false unless Lepus.config.consumers_directory.exist?
73
+
74
+ Dir[config.consumers_directory.join("**/*.rb")].map { |path| Pathname.new(path) }.each do |path|
75
+ next unless path.extname == ".rb"
76
+
77
+ require(path.expand_path.to_s)
78
+ end
79
+ true
80
+ end
81
+
82
+ def self.config
83
+ @config ||= Configuration.new
84
+ end
85
+
86
+ def self.configure
87
+ yield config
88
+ end
89
+ end
90
+
91
+ if defined?(::Rails)
92
+ require_relative "lepus/rails"
93
+ end
94
+
95
+ # loader.eager_load
@@ -0,0 +1,74 @@
1
+ require "puma/plugin"
2
+
3
+ Puma::Plugin.create do
4
+ attr_reader :puma_pid, :lepus_pid, :log_writer, :lepus_supervisor
5
+
6
+ def start(launcher)
7
+ @log_writer = launcher.log_writer
8
+ @puma_pid = $$
9
+
10
+ in_background do
11
+ monitor_lepus
12
+ end
13
+
14
+ launcher.events.on_booted do
15
+ @lepus_pid = fork do
16
+ Thread.new { monitor_puma }
17
+ Lepus::Supervisor.start
18
+ end
19
+ end
20
+
21
+ launcher.events.on_stopped { stop_lepus }
22
+ launcher.events.on_restart { stop_lepus }
23
+ end
24
+
25
+ private
26
+
27
+ def stop_lepus
28
+ Process.waitpid(lepus_pid, Process::WNOHANG)
29
+ log "Stopping Lepus..."
30
+ Process.kill(:INT, lepus_pid) if lepus_pid
31
+ Process.wait(lepus_pid)
32
+ rescue Errno::ECHILD, Errno::ESRCH
33
+ end
34
+
35
+ def monitor_puma
36
+ monitor(:puma_dead?, "Detected Puma has gone away, stopping Lepus...")
37
+ end
38
+
39
+ def monitor_lepus
40
+ monitor(:lepus_dead?, "Detected Lepus has gone away, stopping Puma...")
41
+ end
42
+
43
+ def monitor(process_dead, message)
44
+ loop do
45
+ if send(process_dead)
46
+ log message
47
+ Process.kill(:INT, $$)
48
+ break
49
+ end
50
+ sleep 2
51
+ end
52
+ end
53
+
54
+ def lepus_dead?
55
+ if lepus_started?
56
+ Process.waitpid(lepus_pid, Process::WNOHANG)
57
+ end
58
+ false
59
+ rescue Errno::ECHILD, Errno::ESRCH
60
+ true
61
+ end
62
+
63
+ def lepus_started?
64
+ !lepus_pid.nil?
65
+ end
66
+
67
+ def puma_dead?
68
+ Process.ppid != puma_pid
69
+ end
70
+
71
+ def log(*args)
72
+ log_writer.log(*args)
73
+ end
74
+ end
metadata ADDED
@@ -0,0 +1,290 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: lepus
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1.beta2
5
+ platform: ruby
6
+ authors:
7
+ - Marcos G. Zimmermann
8
+ autorequire:
9
+ bindir: exec
10
+ cert_chain: []
11
+ date: 2025-02-11 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bunny
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
27
+ - !ruby/object:Gem::Dependency
28
+ name: thor
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 0.0.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: 0.0.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: zeitwerk
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: 0.0.0
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: 0.0.0
55
+ - !ruby/object:Gem::Dependency
56
+ name: concurrent-ruby
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: 0.0.0
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: 0.0.0
69
+ - !ruby/object:Gem::Dependency
70
+ name: multi_json
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: 0.0.0
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: 0.0.0
83
+ - !ruby/object:Gem::Dependency
84
+ name: dotenv
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: pry
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rspec
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: rubocop
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: rubocop-performance
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'
153
+ - !ruby/object:Gem::Dependency
154
+ name: rubocop-rspec
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - ">="
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
167
+ - !ruby/object:Gem::Dependency
168
+ name: standard
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - ">="
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
174
+ type: :development
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - ">="
179
+ - !ruby/object:Gem::Version
180
+ version: '0'
181
+ - !ruby/object:Gem::Dependency
182
+ name: webmock
183
+ requirement: !ruby/object:Gem::Requirement
184
+ requirements:
185
+ - - ">="
186
+ - !ruby/object:Gem::Version
187
+ version: '0'
188
+ type: :development
189
+ prerelease: false
190
+ version_requirements: !ruby/object:Gem::Requirement
191
+ requirements:
192
+ - - ">="
193
+ - !ruby/object:Gem::Version
194
+ version: '0'
195
+ description: 'RabbitMQ consumers/producer for ruby applicationsd
196
+
197
+ '
198
+ email:
199
+ - mgzmaster@gmail.com
200
+ executables:
201
+ - lepus
202
+ extensions: []
203
+ extra_rdoc_files: []
204
+ files:
205
+ - ".github/workflows/specs.yml"
206
+ - ".gitignore"
207
+ - ".rspec"
208
+ - ".rubocop.yml"
209
+ - ".tool-versions"
210
+ - CHANGELOG.md
211
+ - Gemfile
212
+ - Gemfile.lock
213
+ - LICENSE.txt
214
+ - README.md
215
+ - Rakefile
216
+ - bin/console
217
+ - bin/setup
218
+ - docker-compose.yml
219
+ - exec/lepus
220
+ - gemfiles/rails52.gemfile
221
+ - gemfiles/rails52.gemfile.lock
222
+ - gemfiles/rails61.gemfile
223
+ - gemfiles/rails61.gemfile.lock
224
+ - lepus.gemspec
225
+ - lib/lepus.rb
226
+ - lib/lepus/app_executor.rb
227
+ - lib/lepus/cli.rb
228
+ - lib/lepus/configuration.rb
229
+ - lib/lepus/consumer.rb
230
+ - lib/lepus/consumer_config.rb
231
+ - lib/lepus/consumer_wrapper.rb
232
+ - lib/lepus/lifecycle_hooks.rb
233
+ - lib/lepus/message.rb
234
+ - lib/lepus/middleware.rb
235
+ - lib/lepus/middlewares/honeybadger.rb
236
+ - lib/lepus/middlewares/json.rb
237
+ - lib/lepus/middlewares/max_retry.rb
238
+ - lib/lepus/primitive/string.rb
239
+ - lib/lepus/process.rb
240
+ - lib/lepus/process_registry.rb
241
+ - lib/lepus/processes.rb
242
+ - lib/lepus/processes/base.rb
243
+ - lib/lepus/processes/callbacks.rb
244
+ - lib/lepus/processes/consumer.rb
245
+ - lib/lepus/processes/interruptible.rb
246
+ - lib/lepus/processes/procline.rb
247
+ - lib/lepus/processes/registrable.rb
248
+ - lib/lepus/processes/runnable.rb
249
+ - lib/lepus/processes/supervised.rb
250
+ - lib/lepus/producer.rb
251
+ - lib/lepus/rails.rb
252
+ - lib/lepus/rails/log_subscriber.rb
253
+ - lib/lepus/rails/railtie.rb
254
+ - lib/lepus/supervisor.rb
255
+ - lib/lepus/supervisor/config.rb
256
+ - lib/lepus/supervisor/maintenance.rb
257
+ - lib/lepus/supervisor/pidfile.rb
258
+ - lib/lepus/supervisor/pidfiled.rb
259
+ - lib/lepus/supervisor/signals.rb
260
+ - lib/lepus/timer.rb
261
+ - lib/lepus/version.rb
262
+ - lib/puma/plugin/lepus.rb
263
+ homepage: https://github.com/marcosgz/lepus
264
+ licenses:
265
+ - MIT
266
+ metadata:
267
+ homepage_uri: https://github.com/marcosgz/lepus
268
+ bug_tracker_uri: https://github.com/marcosgz/lepus/issues
269
+ documentation_uri: https://github.com/marcosgz/lepus
270
+ source_code_uri: https://github.com/marcosgz/lepus
271
+ post_install_message:
272
+ rdoc_options: []
273
+ require_paths:
274
+ - lib
275
+ required_ruby_version: !ruby/object:Gem::Requirement
276
+ requirements:
277
+ - - ">="
278
+ - !ruby/object:Gem::Version
279
+ version: 2.7.0
280
+ required_rubygems_version: !ruby/object:Gem::Requirement
281
+ requirements:
282
+ - - ">"
283
+ - !ruby/object:Gem::Version
284
+ version: 1.3.1
285
+ requirements: []
286
+ rubygems_version: 3.1.6
287
+ signing_key:
288
+ specification_version: 4
289
+ summary: RabbitMQ consumers/producer for ruby applications
290
+ test_files: []