rabbitek 0.3.5 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a36ba46180d4c5e3c28d3d212ff2174c49ef00618f6d49c7defd49ec0768d5ae
4
- data.tar.gz: 25167637efc19c059e73ff8796a19aef890e961ec3c7c891b2b9aba1429d1ef3
3
+ metadata.gz: d6e7e9681a2b0440a71d3ab9ae5f15e614034ab51c6c0339905c5130733e42ad
4
+ data.tar.gz: a6b4d63873a74d3026d576aa9ef6d438e67c79e8ab47cf3634572c62da93ff8d
5
5
  SHA512:
6
- metadata.gz: 33d4cfcad4e769c15e556b93ba40e9c779aa16ab739a889bd2ec01728b1c84cae25096a559aaaf687875f792ad43789612903c9c6c3b4e222b5a3ba0d801df68
7
- data.tar.gz: 22b95c1863b7d22d66c4b9f2eb02a18c734450ac09b3aa999dd6b5f316fa40e45f7f52b101e8924a1c2f2a1e2b8601ba6830b99c4948659825983927c393f421
6
+ metadata.gz: 67cf264c46c092a763e4d0b48b895305d69d915c68489a54d4bd3b220c6f4ce611147afa83d00097ac71b2870390770ebcd5b27c4338fb7550e85ee458af3bd9
7
+ data.tar.gz: d976bcbb478c7c90e964c4f32cf3852a529415e6a3c08414459863a9e4a434dc900734cdeddc7495824853ab4a76e0b02d97566cd2f7325b8ab0ee60bc13da59
@@ -1,3 +1,8 @@
1
+ ## v0.4.0
2
+
3
+ Improvements:
4
+ * Add metrics (universal, you can use e.g. prometheus)
5
+
1
6
  ## v0.3.5
2
7
 
3
8
  Bugfix:
@@ -1,12 +1,13 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rabbitek (0.3.4)
4
+ rabbitek (0.8.0)
5
5
  activesupport (> 3.0)
6
6
  bunny (~> 2.11.0)
7
- oj (~> 3.6)
7
+ oj (> 2.0.0)
8
8
  opentracing (~> 0.4)
9
9
  slop (~> 4.0)
10
+ yabeda (>= 0.6.0)
10
11
 
11
12
  GEM
12
13
  remote: https://rubygems.org/
@@ -52,16 +53,17 @@ GEM
52
53
  i18n (>= 0.7, < 2)
53
54
  minitest (~> 5.1)
54
55
  tzinfo (~> 1.1)
55
- amq-protocol (2.3.0)
56
+ amq-protocol (2.3.2)
56
57
  arel (9.0.0)
57
58
  ast (2.4.0)
58
59
  builder (3.2.4)
59
60
  bunny (2.11.0)
60
61
  amq-protocol (~> 2.3.0)
61
62
  coderay (1.1.2)
62
- concurrent-ruby (1.1.5)
63
+ concurrent-ruby (1.1.6)
63
64
  crass (1.0.6)
64
65
  diff-lcs (1.3)
66
+ dry-initializer (3.0.3)
65
67
  erubi (1.9.0)
66
68
  globalid (0.4.2)
67
69
  activesupport (>= 4.2.0)
@@ -83,7 +85,7 @@ GEM
83
85
  nio4r (2.5.2)
84
86
  nokogiri (1.10.7)
85
87
  mini_portile2 (~> 2.4.0)
86
- oj (3.10.1)
88
+ oj (3.10.8)
87
89
  opentracing (0.5.0)
88
90
  parallel (1.12.1)
89
91
  parser (2.5.1.2)
@@ -143,7 +145,7 @@ GEM
143
145
  ruby-progressbar (~> 1.7)
144
146
  unicode-display_width (~> 1.0, >= 1.0.1)
145
147
  ruby-progressbar (1.10.0)
146
- slop (4.7.0)
148
+ slop (4.8.2)
147
149
  sprockets (4.0.0)
148
150
  concurrent-ruby (~> 1.0)
149
151
  rack (> 1, < 3)
@@ -159,6 +161,9 @@ GEM
159
161
  websocket-driver (0.7.1)
160
162
  websocket-extensions (>= 0.1.0)
161
163
  websocket-extensions (0.1.4)
164
+ yabeda (0.6.1)
165
+ concurrent-ruby
166
+ dry-initializer
162
167
 
163
168
  PLATFORMS
164
169
  ruby
@@ -173,4 +178,4 @@ DEPENDENCIES
173
178
  rubocop (~> 0.58.0)
174
179
 
175
180
  BUNDLED WITH
176
- 2.0.2
181
+ 2.1.4
data/README.md CHANGED
@@ -11,6 +11,7 @@ High performance, easy to use background job processing library for Ruby using R
11
11
  * OpenTracing (http://opentracing.io/) instrumentation
12
12
  * NewRelic instrumentation for sending errors
13
13
  * Sentry instrumentation for sending errors
14
+ * Metrics (using [Yabeda](https://github.com/yabeda-rb/yabeda))
14
15
 
15
16
  ## Installation
16
17
 
@@ -89,7 +90,6 @@ You can schedule jobs e.g.: `ExampleCustomer.perform_async(some: :payload)`
89
90
  * dead queue
90
91
  * CRON jobs
91
92
  * extended docs and how to
92
- * prometheus metrics
93
93
 
94
94
 
95
95
  ## Development
@@ -6,6 +6,7 @@ require 'bunny'
6
6
  require 'oj'
7
7
  require 'opentracing'
8
8
  require 'logger'
9
+ require 'yabeda'
9
10
 
10
11
  # active_support
11
12
  require 'active_support/core_ext/module/attribute_accessors'
@@ -54,3 +55,15 @@ module Rabbitek
54
55
  @bunny_connection ||= BunnyConnection.initialize_connection
55
56
  end
56
57
  end
58
+
59
+ Yabeda.configure do
60
+ group :rabbitek do
61
+ counter :processed_messages_count, comment: 'Total number of all messages'
62
+ counter :errored_messages_count, comment: 'Total number of errored messages'
63
+ histogram :processed_messages_runtime do
64
+ comment 'How long it takes to process message'
65
+ unit :seconds
66
+ buckets [0.1, 0.5, 1, 5, 10, 30, 60]
67
+ end
68
+ end
69
+ end
@@ -14,9 +14,12 @@ module Rabbitek
14
14
  class CLI
15
15
  include ::Rabbitek::Loggable
16
16
 
17
- def run
17
+ def run # rubocop:disable Metrics/AbcSize
18
18
  opts
19
19
  require_application
20
+
21
+ Yabeda.configure! unless Yabeda.already_configured?
22
+
20
23
  map_consumer_workers!
21
24
 
22
25
  start_log
@@ -6,7 +6,7 @@ module Rabbitek
6
6
  class Batcher
7
7
  def initialize(consumer)
8
8
  @consumer = consumer
9
- @batch_size = consumer.batch_size
9
+ @batch_size = consumer.opts[:batch][:of]
10
10
  @batch = []
11
11
  end
12
12
 
@@ -52,16 +52,16 @@ module Rabbitek
52
52
  Message.new(delivery_info: delivery_info, properties: properties, payload: payload)
53
53
  end
54
54
 
55
- def batch_size
56
- self.class.batch
55
+ def opts
56
+ self.class.opts
57
57
  end
58
58
 
59
59
  module ClassMethods # rubocop:disable Style/Documentation
60
- attr_accessor :rabbit_options_hash, :batch
60
+ attr_accessor :rabbit_options_hash, :opts
61
61
 
62
62
  def rabbit_options(opts)
63
63
  self.rabbit_options_hash = default_rabbit_options(opts).with_indifferent_access.merge(opts)
64
- self.batch = opts[:batch]
64
+ self.opts = opts
65
65
  end
66
66
 
67
67
  def perform_async(payload, opts: {}, channel: nil)
@@ -13,7 +13,7 @@ module Rabbitek
13
13
  def call(consumer, message)
14
14
  super
15
15
  rescue StandardError
16
- retry_message(consumer, message) unless consumer.batch_size
16
+ retry_message(consumer, message) unless consumer.opts[:batch]
17
17
  raise
18
18
  end
19
19
 
@@ -11,19 +11,40 @@ module Rabbitek
11
11
  include Loggable
12
12
 
13
13
  def call(consumer, message)
14
- info(message: 'Starting', consumer: message.delivery_info.routing_key, jid: consumer.jid)
14
+ log_started(consumer, message)
15
15
 
16
- start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
16
+ start = current_time
17
17
 
18
18
  super
19
19
  ensure
20
+ total_time = current_time - start
21
+
22
+ log_finished(consumer, message, total_time)
23
+ metrics_measure_time(consumer, total_time)
24
+ end
25
+
26
+ private
27
+
28
+ def current_time
29
+ Process.clock_gettime(Process::CLOCK_MONOTONIC)
30
+ end
31
+
32
+ def log_started(consumer, message)
33
+ info(message: 'Starting job', consumer: message.delivery_info.routing_key, jid: consumer.jid)
34
+ end
35
+
36
+ def log_finished(consumer, message, total_time)
20
37
  info(
21
- message: 'Finished',
38
+ message: 'Finished job',
22
39
  consumer: message.delivery_info.routing_key,
23
- time: Process.clock_gettime(Process::CLOCK_MONOTONIC) - start,
40
+ time: total_time,
24
41
  jid: consumer.jid
25
42
  )
26
43
  end
44
+
45
+ def metrics_measure_time(consumer, total_time)
46
+ Yabeda.rabbitek.processed_messages_runtime.measure({ consumer: consumer.class }, total_time)
47
+ end
27
48
  end
28
49
  end
29
50
  end
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'forwardable'
4
+
5
+ module Rabbitek
6
+ ##
7
+ # Single message processor
8
+ class MessageProcessor
9
+ include Loggable
10
+ extend Forwardable
11
+
12
+ def initialize(starter, delivery_info, properties, payload)
13
+ @starter = starter
14
+ @delivery_info = delivery_info
15
+ @properties = properties
16
+ @payload = payload
17
+ end
18
+
19
+ def process
20
+ consumer.set_context
21
+
22
+ metrics_add_processed_count
23
+
24
+ hook_walker = Utils::HookWalker.new(Rabbitek.config.server_hooks)
25
+ hook_walker.call!(consumer, message) { |*args| run_job(*args) }
26
+ rescue StandardError => e
27
+ on_message_errored(e)
28
+ end
29
+
30
+ private
31
+
32
+ attr_reader :starter, :delivery_info, :properties, :payload
33
+ def_delegators :starter, :channel, :work_queue, :retry_or_delayed_queue, :retry_or_delayed_exchange
34
+
35
+ def run_job(modified_consumer, message)
36
+ if modified_consumer.opts[:batch]
37
+ run_job_batched(modified_consumer, message)
38
+ else
39
+ modified_consumer.perform(message)
40
+ modified_consumer.ack!(message.delivery_info) unless modified_consumer.opts[:manual_ack]
41
+ end
42
+ end
43
+
44
+ def run_job_batched(modified_consumer, message)
45
+ Batcher.new(modified_consumer).perform(message) do |batch|
46
+ modified_consumer.perform(batch)
47
+ modified_consumer.ack!(batch.last.delivery_info, true) unless modified_consumer.opts[:manual_ack]
48
+ end
49
+ end
50
+
51
+ def on_message_errored(exception)
52
+ error(message: exception.inspect, backtrace: exception.backtrace, consumer: consumer.class, jid: consumer.jid)
53
+ metrics_add_errored_count
54
+ end
55
+
56
+ def metrics_add_processed_count
57
+ Yabeda.rabbitek.processed_messages_count.increment(metrics_tags, by: 1)
58
+ end
59
+
60
+ def metrics_add_errored_count
61
+ Yabeda.rabbitek.errored_messages_count.increment(metrics_tags, by: 1)
62
+ end
63
+
64
+ def message
65
+ @message ||= Message.new(delivery_info: delivery_info, properties: properties, payload: payload)
66
+ end
67
+
68
+ def consumer
69
+ @consumer ||= consumer_instance(message.delivery_info.routing_key)
70
+ end
71
+
72
+ def consumer_instance(routing_key)
73
+ Thread.current[:worker_classes] ||= {}
74
+ klass = Thread.current[:worker_classes][routing_key] ||= routing_key.constantize
75
+ klass.new(channel, work_queue, retry_or_delayed_queue, retry_or_delayed_exchange)
76
+ rescue NameError
77
+ nil # TODO: to dead queue
78
+ end
79
+
80
+ def metrics_tags
81
+ { consumer: consumer.class }
82
+ end
83
+ end
84
+ end
@@ -17,58 +17,18 @@ module Rabbitek
17
17
  setup_bindings!
18
18
 
19
19
  work_queue.subscribe(manual_ack: true) do |delivery_info, properties, payload|
20
- message = Message.new(delivery_info: delivery_info, properties: properties, payload: payload)
21
- Rabbitek.reloader.call { on_message_received(message) }
20
+ Rabbitek.reloader.call do
21
+ MessageProcessor.new(self, delivery_info, properties, payload).process
22
+ end
22
23
  end
23
24
  end
24
25
 
25
- private
26
-
27
- attr_reader :connection, :queue_name, :consumers, :opts
28
-
29
- def setup_bindings!
30
- consumers.each do |worker_class|
31
- work_queue.bind(work_exchange, routing_key: worker_class.to_s)
32
- retry_or_delayed_queue.bind(retry_or_delayed_exchange, routing_key: worker_class.to_s)
33
- end
34
- end
35
-
36
- def on_message_received(message)
37
- consumer = consumer_instance(message.delivery_info.routing_key)
38
- consumer.set_context
39
-
40
- hook_walker = Utils::HookWalker.new(Rabbitek.config.server_hooks)
41
-
42
- hook_walker.call!(consumer, message) do |*args|
43
- run_job(*args)
44
- end
45
- rescue StandardError => e
46
- error(message: e.inspect, backtrace: e.backtrace, consumer: consumer.class, jid: consumer.jid)
47
- end
48
-
49
- def run_job(consumer, message)
50
- if consumer.class.batch
51
- run_job_batched(consumer, message)
52
- else
53
- consumer.perform(message)
54
- consumer.ack!(message.delivery_info)
55
- end
56
- end
57
-
58
- def consumer_instance(routing_key)
59
- Thread.current[:worker_classes] ||= {}
60
- klass = Thread.current[:worker_classes][routing_key] ||= routing_key.constantize
61
- klass.new(channel, work_queue, retry_or_delayed_queue, retry_or_delayed_exchange)
62
- rescue NameError
63
- nil # TODO: to dead queue
64
- end
65
-
66
26
  def channel
67
27
  @channel ||= begin
68
- channel = connection.create_channel
69
- channel.basic_qos(opts[:basic_qos]) if opts[:basic_qos].present?
70
- channel
71
- end
28
+ channel = connection.create_channel
29
+ channel.basic_qos(opts[:basic_qos]) if opts[:basic_qos].present?
30
+ channel
31
+ end
72
32
  end
73
33
 
74
34
  def work_exchange
@@ -95,10 +55,14 @@ module Rabbitek
95
55
  )
96
56
  end
97
57
 
98
- def run_job_batched(consumer, message)
99
- Batcher.new(consumer).perform(message) do |batch|
100
- consumer.perform(batch)
101
- consumer.ack!(batch.last.delivery_info, true)
58
+ private
59
+
60
+ attr_reader :connection, :queue_name, :consumers, :opts
61
+
62
+ def setup_bindings!
63
+ consumers.each do |worker_class|
64
+ work_queue.bind(work_exchange, routing_key: worker_class.to_s)
65
+ retry_or_delayed_queue.bind(retry_or_delayed_exchange, routing_key: worker_class.to_s)
102
66
  end
103
67
  end
104
68
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Rabbitek
4
- VERSION = '0.3.5'
4
+ VERSION = '0.8.0'
5
5
  end
@@ -31,9 +31,10 @@ Gem::Specification.new do |spec|
31
31
 
32
32
  spec.add_dependency 'activesupport', '> 3.0'
33
33
  spec.add_dependency 'bunny', '~> 2.11.0'
34
- spec.add_dependency 'oj', '~> 3.6'
34
+ spec.add_dependency 'oj', '> 2.0.0'
35
35
  spec.add_dependency 'opentracing', '~> 0.4'
36
36
  spec.add_dependency 'slop', '~> 4.0'
37
+ spec.add_dependency 'yabeda', '>= 0.6.0'
37
38
 
38
39
  spec.add_development_dependency 'bundler', '~> 2.0'
39
40
  spec.add_development_dependency 'pry'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rabbitek
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.5
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Boostcom
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-01-15 00:00:00.000000000 Z
11
+ date: 2020-07-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -42,16 +42,16 @@ dependencies:
42
42
  name: oj
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - "~>"
45
+ - - ">"
46
46
  - !ruby/object:Gem::Version
47
- version: '3.6'
47
+ version: 2.0.0
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - "~>"
52
+ - - ">"
53
53
  - !ruby/object:Gem::Version
54
- version: '3.6'
54
+ version: 2.0.0
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: opentracing
57
57
  requirement: !ruby/object:Gem::Requirement
@@ -80,6 +80,20 @@ dependencies:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
82
  version: '4.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: yabeda
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: 0.6.0
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: 0.6.0
83
97
  - !ruby/object:Gem::Dependency
84
98
  name: bundler
85
99
  requirement: !ruby/object:Gem::Requirement
@@ -204,6 +218,7 @@ files:
204
218
  - lib/rabbitek/server/hooks/retry.rb
205
219
  - lib/rabbitek/server/hooks/time_tracker.rb
206
220
  - lib/rabbitek/server/message.rb
221
+ - lib/rabbitek/server/message_processor.rb
207
222
  - lib/rabbitek/server/retryer.rb
208
223
  - lib/rabbitek/server/server_hook.rb
209
224
  - lib/rabbitek/server/starter.rb
@@ -221,7 +236,7 @@ metadata:
221
236
  source_code_uri: https://github.com/Boostcom/rabbitek
222
237
  changelog_uri: https://github.com/Boostcom/rabbitek/blob/master/CHANGELOG.md
223
238
  bug_tracker_uri: https://github.com/Boostcom/rabbitek/issues
224
- post_install_message:
239
+ post_install_message:
225
240
  rdoc_options: []
226
241
  require_paths:
227
242
  - lib
@@ -236,8 +251,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
236
251
  - !ruby/object:Gem::Version
237
252
  version: '0'
238
253
  requirements: []
239
- rubygems_version: 3.0.3
240
- signing_key:
254
+ rubygems_version: 3.1.2
255
+ signing_key:
241
256
  specification_version: 4
242
257
  summary: High performance background job processing
243
258
  test_files: []