fleck 2.1.2 → 2.2.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: ecd7fdd80e3e92c7cfe1975c450d5f0cb7663dd91925bb2180b084a839aac0f8
4
- data.tar.gz: 7f06df1290c2dd621493b705573b6072d7dbaff0385e53f5e72a1d9564411483
3
+ metadata.gz: 469551dc2d0172cea61bba8b982d70a6f8b68258f956c359602f02487490a77c
4
+ data.tar.gz: e2c0999b1da9cbf39246dd70dbeb3fcdec98072779a5bcc124ec4313c8a8e762
5
5
  SHA512:
6
- metadata.gz: efc1b9f98d31737f4d92e845f30c072e43be49c40eac3f7350cc9aa4da25d2927da77cecf019dd3f6bc3580b3cde9ccef9494ce62b6dc8c37b557646b6331e22
7
- data.tar.gz: 3cabbcac002ec6a030ac6c0eb1ebd75045b1a04b0d0e6f20697800da04c4f6d1f1389c27fcb064b18918e6ed839f790f4cbcd2d15c2bd37282745e54ef6df935
6
+ metadata.gz: b547f65455632875f7490343f19dfb6e0cc26e54f26358991786c983a9ed812f777046232c6bbd45dd7bda1e016899d0fd0cb9f58aa05273589f5a286c92a158
7
+ data.tar.gz: '03388d8f65b3ad560bcf62f6c9dddbd5a952d6f9a38a477457cab601259313c3ebd55b3ae7735c8f5dff5a4499215c5f7e0fac3c9c733f79ac8bae889b06eb20'
data/CHANGELOG.md CHANGED
@@ -2,17 +2,47 @@
2
2
 
3
3
  ## develop ##
4
4
 
5
+ ### TAGS ###
6
+
7
+ Below you can see the CHANGELOG of **Fleck** gem by version number.
8
+
9
+ #### v2.2.0 (22 Dicember 2022) #####
10
+
11
+ - **NEW** Implemented the feature which allows to add a modifier `lambda` to `param` decorator,
12
+ so that the value of parameter can be modified before proceeding with action execution.
13
+ Example: `param :name, ->(v) { v.to_s.strip.downcase }` will automatically convert the value of `name` parameter to string, will remove heading and trailing spaces and will transform to lower case.
14
+ - **FIX** Correctly perform param `:max` validation.
15
+ - **FIX** Move `HashWithIndifferentAccess` class under `Fleck` module, in order to avoid conflict with `ActiveSupport::HashWithIndifferentAccess`.
16
+
17
+ #### v2.1.3 (10 February 2022) #####
18
+
19
+ - **FIX** Correct nesting for `Fleck::HostRating` methods, in order to have correct context and visibility.
20
+
21
+ #### v2.1.2 (10 February 2022) ####
22
+
23
+ - **FIX** Autoload Fleck::HostRating from `fleck.rb`, instead of autoloading it from `configuration.rb`.
24
+
25
+ #### v2.1.1 (9 February 2022) ####
26
+
27
+ - **FIX** Correctly handle cases when `#ok!` helper method is used and a hash body is passed as argument.
28
+
29
+ #### v2.1.0 (9 February 2022) ####
30
+
31
+ - **NEW** Added automatic params and headers logging when logger level is set to DEBUG.
32
+
33
+ #### v2.0.0 (31 Jannuary 2022) ####
34
+
5
35
  - **BREAKING CHANGE** Updated minimum required Ruby version to >= 2.5.
6
- - **NEW** Refactore `Fleck::Consumer` in order to have a better code structure.
36
+ - **NEW** Refactored `Fleck::Consumer` in order to have a better code structure.
7
37
  - **NEW** Implemented response helpers, which allow to terminate the request with desired status code and message.
8
38
  - **NEW** Implemented action decorators, which allow to define an action and it's parameters directly before the method.
9
39
  - **NEW** Implemented action params automatic validation, which can be set by using action decorators.
10
40
 
11
- ## v1.0.1 (2 April 2020) ##
41
+ #### v1.0.1 (2 April 2020) ####
12
42
 
13
43
  - **BREAKING CHANGE** Updateg gemset, in order to be able to use new versions of Ruby.
14
44
 
15
- ## v0.7.0 (21 June 2016) ##
45
+ #### v0.7.0 (21 June 2016) ####
16
46
 
17
47
  - **NEW** Added multihost support to Fleck configuration, that allows to manage network failure situations and to choose the best options from the list of available hosts.
18
48
  This feature uses `Fleck::HostRating` to collect TCP latency data about each provided host, so that when a new connection is required, the host with lowest latency
@@ -22,7 +52,7 @@
22
52
  - **NEW** Implemented `:deprecated?` method for `Fleck::Consumer::Response`.
23
53
  - **NEW** Store client IP address to requests headers, in order to be able to trace requests origin when multiple clients making requests to the same consumer type.
24
54
 
25
- ## v0.6.0 (16 June 2016)##
55
+ #### v0.6.0 (16 June 2016) ####
26
56
 
27
57
  - **NEW** __(BREAKING CHANGE)__ Use `"fleck"` exchange for RPC simulation, so that reply queues could be used in a RabbitMQ Federation configuration.
28
58
  Be careful when upgrading `Fleck::Consumer` from version `v0.5.x` or below, because now `Fleck::Consumer` will send responses to a `:direct` exchange
@@ -32,12 +62,12 @@
32
62
  - **NEW** Implemented the feature that allows to start consumer in a blocking way.
33
63
  - **NEW** Added `:prefetch` and `:mandatory` options to `Fleck::Consumer` configuration options.
34
64
 
35
- ## v0.5.1 (20 April 2016) ##
65
+ #### v0.5.1 (20 April 2016) ####
36
66
 
37
67
  - **FIX** Don't expire requests with multiple responses if any response is received. Treat that kind of request as expired if no response has been received
38
68
  until the request expiration.
39
69
 
40
- ## v0.5.0 (20 April 2016) ##
70
+ #### v0.5.0 (20 April 2016) ####
41
71
 
42
72
  - **NEW** Added `:autostart` option to `Fleck::Consumer` configuration, so that the developer could decide to start the consumer manually or automatically. By default
43
73
  the consumer will start automatically.
@@ -56,11 +86,11 @@
56
86
  - **NEW** Add `app_name` configuration, that allows to configure the default `app_id` to set for RabbitMQ messages.
57
87
  - **NEW** Add process ID to logs, so that if you have multiple instances of the same application writting to the same log file, you'll be able to filter logs by process ID. Also changed logs format.
58
88
 
59
- ## v0.4.1 (18 April 2016) ##
89
+ #### v0.4.1 (18 April 2016) ####
60
90
 
61
91
  - **FIX** Fixed a bug of `Fleck::Consumer::Request` class, that was causing errors when RabbitMQ message header wasn't set.
62
92
 
63
- ## v0.4.0 (15 April 2016) ##
93
+ #### v0.4.0 (15 April 2016) ####
64
94
 
65
95
  - **NEW** Support different types of exchanges in both `Fleck::Client` and `Fleck::Consumer`.
66
96
  - **FIX** Use `auto_delete` queue for `Fleck::Client`, so that it is deleted when the client is terminated.
@@ -70,7 +100,7 @@
70
100
  `:params` option will be converted to JSON.
71
101
  - **NEW** Add `:action` option to `Fleck::Client::Request`, which will replace the action passed within `:headers` hash.
72
102
 
73
- ## v0.3.0 (1 April 2016) ##
103
+ #### v0.3.0 (1 April 2016) ####
74
104
 
75
105
  - **FIX** Use `:compat` mode when using `Oj` gem to dump/load JSON content.
76
106
  - **FIX** Prevent unnecessary `Fleck::Request` lock for response reception if the response already received.
@@ -83,7 +113,7 @@
83
113
  failed requests aren't requeued. You should call `response.reject(requeue: true)` within the `on_message` method, if you want to requeue the processing
84
114
  message.
85
115
 
86
- ## v0.2.0 (18 February 2016) ##
116
+ #### v0.2.0 (18 February 2016) ####
87
117
 
88
118
  - **NEW** `timeout` (synchronous requests only) and `queue` support for `Fleck::Client#request`
89
119
  - **NEW** Keywords arguments for `Fleck::Client#request` method (ex. `client.request(headers: {h1: v1, ...}, params: {p1: v2, ...}`)
data/fleck.gemspec CHANGED
@@ -1,37 +1,37 @@
1
- # frozen_string_literal: true
2
-
3
- lib = File.expand_path(__dir__)
4
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
- require 'lib/fleck/version'
6
-
7
- Gem::Specification.new do |spec|
8
- spec.name = 'fleck'
9
- spec.platform = 'ruby'
10
- spec.version = Fleck::VERSION
11
- spec.authors = ['Groza Sergiu']
12
- spec.email = ['serioja90@gmail.com']
13
-
14
- spec.summary = %(A Ruby gem for syncronous and asyncronous communication via Message Queue services.)
15
- spec.description = %(
16
- Fleck is a library for syncronous and asyncronous communication over Message Queues services. Unlike a common
17
- HTTP communication, Fleck requests and responses are pure JSON messages.
18
- )
19
- spec.homepage = 'https://github.com/serioja90/fleck'
20
- spec.license = 'MIT'
21
-
22
- spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
23
- spec.bindir = 'exe'
24
- spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
25
- spec.require_paths = ['lib']
26
-
27
- spec.required_ruby_version = '>= 2.5'
28
-
29
- spec.add_development_dependency 'bundler', '>= 2.2.33'
30
- spec.add_development_dependency 'rake', '~> 13.0'
31
- spec.add_development_dependency 'rspec', '~> 3.9'
32
- spec.add_dependency 'bunny', '~> 2.14'
33
- spec.add_dependency 'oj', '~> 3.10'
34
- spec.add_dependency 'rainbow', '~> 2.2'
35
- spec.add_dependency 'thread_safe', '~> 0.3'
36
- spec.add_dependency 'ztimer', '~> 0.6'
37
- end
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path(__dir__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require 'lib/fleck/version'
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = 'fleck'
9
+ spec.platform = 'ruby'
10
+ spec.version = Fleck::VERSION
11
+ spec.authors = ['Groza Sergiu']
12
+ spec.email = ['serioja90@gmail.com']
13
+
14
+ spec.summary = %(A Ruby gem for syncronous and asyncronous communication via Message Queue services.)
15
+ spec.description = %(
16
+ Fleck is a library for syncronous and asyncronous communication over Message Queues services. Unlike a common
17
+ HTTP communication, Fleck requests and responses are pure JSON messages.
18
+ )
19
+ spec.homepage = 'https://github.com/serioja90/fleck'
20
+ spec.license = 'MIT'
21
+
22
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
23
+ spec.bindir = 'exe'
24
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
25
+ spec.require_paths = ['lib']
26
+
27
+ spec.required_ruby_version = '>= 2.5'
28
+
29
+ spec.add_development_dependency 'bundler', '>= 2.2.33'
30
+ spec.add_development_dependency 'rake', '~> 13.0'
31
+ spec.add_development_dependency 'rspec', '~> 3.9'
32
+ spec.add_dependency 'bunny', '~> 2.14'
33
+ spec.add_dependency 'oj', '~> 3.10'
34
+ spec.add_dependency 'rainbow', '~> 2.2'
35
+ spec.add_dependency 'thread_safe', '~> 0.3'
36
+ spec.add_dependency 'ztimer', '~> 0.6'
37
+ end
@@ -1,7 +1,7 @@
1
- # frozen_string_literal: true
2
-
3
- module Fleck
4
- # A shorthand class for custom consumers definitions.
5
- class Consumer < Fleck::Core::Consumer
6
- end
7
- end
1
+ # frozen_string_literal: true
2
+
3
+ module Fleck
4
+ # A shorthand class for custom consumers definitions.
5
+ class Consumer < Fleck::Core::Consumer
6
+ end
7
+ end
@@ -13,12 +13,13 @@ module Fleck
13
13
  'hash' => 'object'
14
14
  }.freeze
15
15
 
16
- attr_reader :name, :type, :options
16
+ attr_reader :name, :type, :modifier, :options
17
17
 
18
- def initialize(name, type, options = {})
18
+ def initialize(name, modifier = nil, **options)
19
19
  @name = name
20
- @type = type
21
20
  @options = options
21
+ @modifier = modifier
22
+ @type = @options&.fetch(:type)
22
23
 
23
24
  check_options!
24
25
  end
@@ -32,13 +33,14 @@ module Fleck
32
33
  end
33
34
 
34
35
  def validate(value)
35
- Validation.new(name, type, value, options)
36
+ Validation.new(name, type, value, modifier, **options)
36
37
  end
37
38
 
38
39
  private
39
40
 
40
41
  def check_options!
41
42
  check_type!
43
+ check_modifier!
42
44
  check_required!
43
45
  check_default!
44
46
  check_min_max!
@@ -55,6 +57,12 @@ module Fleck
55
57
  raise "Invalid param type: #{@type.inspect}" unless valid_type
56
58
  end
57
59
 
60
+ def check_modifier!
61
+ return if @modifier.nil? || @modifier.is_a?(Proc)
62
+
63
+ raise "Invalid modifier, lambda or Proc expected, got #{@modifier.class}"
64
+ end
65
+
58
66
  def check_required!
59
67
  options[:required] = (options[:required] == true)
60
68
  end
@@ -1,111 +1,111 @@
1
- # frozen_string_literal: true
2
-
3
- module Fleck
4
- module Core
5
- class Consumer
6
- # Base methods for consumer setup, start and termination.
7
- module Base
8
- def self.included(base)
9
- base.extend ClassMethods
10
- base.send :include, InstanceMethods
11
- end
12
-
13
- # Defines class methods to import when `Autostart` module is imported.
14
- module ClassMethods
15
- attr_accessor :consumers, :initialize_block, :lock, :condition
16
-
17
- def inherited(subclass)
18
- super
19
- return if subclass == Fleck::Consumer
20
-
21
- init_consumer(subclass)
22
- autostart(subclass)
23
- Fleck.register_consumer(subclass)
24
- end
25
-
26
- def initialize(&block)
27
- self.initialize_block = block
28
- end
29
-
30
- def start(block: false)
31
- consumers.each(&:start)
32
- wait_termination if block
33
- end
34
-
35
- def wait_termination
36
- lock.synchronize { condition.wait(lock) }
37
- end
38
-
39
- def on_terminate(consumer)
40
- consumers.delete consumer
41
- terminate if consumers.empty?
42
- end
43
-
44
- def terminate
45
- consumers.each(&:terminate)
46
- lock.synchronize { condition.signal }
47
- end
48
-
49
- protected
50
-
51
- def init_consumer(subclass)
52
- configure_logger(subclass)
53
-
54
- subclass.lock = Mutex.new
55
- subclass.condition = ConditionVariable.new
56
-
57
- subclass.configs = Fleck.config.default_options
58
- subclass.actions_map = {}
59
- subclass.consumers = []
60
- end
61
-
62
- def configure_logger(subclass)
63
- subclass.logger = Fleck.logger.clone
64
- subclass.logger.progname = subclass.to_s
65
- subclass.logger.debug "Setting defaults for #{subclass.to_s.color(:yellow)} consumer"
66
- end
67
-
68
- def autostart(subclass)
69
- # Use TracePoint to autostart the consumer when ready
70
- trace = TracePoint.new(:end) do |tp|
71
- if tp.self == subclass
72
- # disable tracing when we reach the end of the subclass
73
- trace.disable
74
- # create a new instance of the subclass, in order to start the consumer
75
- [subclass.configs[:concurrency].to_i, 1].max.times do |i|
76
- subclass.consumers << subclass.new(i)
77
- end
78
- end
79
- end
80
- trace.enable
81
- end
82
- end
83
-
84
- # Defines instance methods to import when `Autostart` module is imported.
85
- module InstanceMethods
86
- def autostart?
87
- configs[:autostart].nil? || configs[:autostart]
88
- end
89
-
90
- def start
91
- logger.info "Launching #{self.class.to_s.color(:yellow)} consumer ..."
92
- connect!
93
- create_channel!
94
- subscribe!
95
- end
96
-
97
- def terminate
98
- pause
99
-
100
- return if channel.nil? || channel.closed?
101
-
102
- channel.close
103
-
104
- logger.info 'Consumer successfully terminated.'
105
- self.class.on_terminate(self)
106
- end
107
- end
108
- end
109
- end
110
- end
111
- end
1
+ # frozen_string_literal: true
2
+
3
+ module Fleck
4
+ module Core
5
+ class Consumer
6
+ # Base methods for consumer setup, start and termination.
7
+ module Base
8
+ def self.included(base)
9
+ base.extend ClassMethods
10
+ base.send :include, InstanceMethods
11
+ end
12
+
13
+ # Defines class methods to import when `Autostart` module is imported.
14
+ module ClassMethods
15
+ attr_accessor :consumers, :initialize_block, :lock, :condition
16
+
17
+ def inherited(subclass)
18
+ super
19
+ return if subclass == Fleck::Consumer
20
+
21
+ init_consumer(subclass)
22
+ autostart(subclass)
23
+ Fleck.register_consumer(subclass)
24
+ end
25
+
26
+ def initialize(&block)
27
+ self.initialize_block = block
28
+ end
29
+
30
+ def start(block: false)
31
+ consumers.each(&:start)
32
+ wait_termination if block
33
+ end
34
+
35
+ def wait_termination
36
+ lock.synchronize { condition.wait(lock) }
37
+ end
38
+
39
+ def on_terminate(consumer)
40
+ consumers.delete consumer
41
+ terminate if consumers.empty?
42
+ end
43
+
44
+ def terminate
45
+ consumers.each(&:terminate)
46
+ lock.synchronize { condition.signal }
47
+ end
48
+
49
+ protected
50
+
51
+ def init_consumer(subclass)
52
+ configure_logger(subclass)
53
+
54
+ subclass.lock = Mutex.new
55
+ subclass.condition = ConditionVariable.new
56
+
57
+ subclass.configs = Fleck.config.default_options
58
+ subclass.actions_map = {}
59
+ subclass.consumers = []
60
+ end
61
+
62
+ def configure_logger(subclass)
63
+ subclass.logger = Fleck.logger.clone
64
+ subclass.logger.progname = subclass.to_s
65
+ subclass.logger.debug "Setting defaults for #{subclass.to_s.color(:yellow)} consumer"
66
+ end
67
+
68
+ def autostart(subclass)
69
+ # Use TracePoint to autostart the consumer when ready
70
+ trace = TracePoint.new(:end) do |tp|
71
+ if tp.self == subclass
72
+ # disable tracing when we reach the end of the subclass
73
+ trace.disable
74
+ # create a new instance of the subclass, in order to start the consumer
75
+ [subclass.configs[:concurrency].to_i, 1].max.times do |i|
76
+ subclass.consumers << subclass.new(i)
77
+ end
78
+ end
79
+ end
80
+ trace.enable
81
+ end
82
+ end
83
+
84
+ # Defines instance methods to import when `Autostart` module is imported.
85
+ module InstanceMethods
86
+ def autostart?
87
+ configs[:autostart].nil? || configs[:autostart]
88
+ end
89
+
90
+ def start
91
+ logger.info "Launching #{self.class.to_s.color(:yellow)} consumer ..."
92
+ connect!
93
+ create_channel!
94
+ subscribe!
95
+ end
96
+
97
+ def terminate
98
+ pause
99
+
100
+ return if channel.nil? || channel.closed?
101
+
102
+ channel.close
103
+
104
+ logger.info 'Consumer successfully terminated.'
105
+ self.class.on_terminate(self)
106
+ end
107
+ end
108
+ end
109
+ end
110
+ end
111
+ end
@@ -49,11 +49,11 @@ module Fleck
49
49
  method_options[:description] = description if description
50
50
  end
51
51
 
52
- def param(name, options = {})
53
- method_options[:params][name] = ActionParam.new(name, options[:type], options)
52
+ def param(name, modifier = nil, **options)
53
+ method_options[:params][name] = ActionParam.new(name, modifier, **options)
54
54
  end
55
55
 
56
- def header(name, options = {})
56
+ def header(name, modifier = nil, **options)
57
57
  raise 'Not Implemented'
58
58
  # method_options[:headers][name] = ActionParam.new(name, options[:type], options)
59
59
  end
@@ -6,9 +6,10 @@ module Fleck
6
6
  class Validation
7
7
  attr_reader :value, :errors
8
8
 
9
- def initialize(name, type, value, options = {})
9
+ def initialize(name, type, value, modifier = nil, **options)
10
10
  @name = name
11
11
  @type = type
12
+ @modifier = modifier
12
13
  @value = value || options[:default]
13
14
  @required = (options[:required] == true) # default: trues
14
15
  @allow_blank = (options[:allow_blank] != false) # default: false
@@ -43,6 +44,8 @@ module Fleck
43
44
  when 'hash' then validate_hash!
44
45
  when 'array' then validate_array!
45
46
  end
47
+
48
+ apply_modifier!
46
49
  end
47
50
 
48
51
  def validate_string!
@@ -141,13 +144,19 @@ module Fleck
141
144
 
142
145
  def check_min_max!
143
146
  add_error(:min, "#{@name} should be greater than #{@min}") if @min && value < @min
144
- add_error(:max, "#{@name} should be smaller than #{@max}") if @max && value < @max
147
+ add_error(:max, "#{@name} should be smaller than #{@max}") if @max && value > @max
145
148
  end
146
149
 
147
150
  def check_clamp!
148
151
  @value = @value.clamp(@clamp.first || -Float::INFINITY, @clamp.last || Float::INFINITY)
149
152
  end
150
153
 
154
+ def apply_modifier!
155
+ return if @modifier.nil?
156
+
157
+ @value = @modifier.call(@value)
158
+ end
159
+
151
160
  def numeric?
152
161
  !Float(value).nil?
153
162
  rescue ArgumentError
@@ -1,166 +1,166 @@
1
- # frozen_string_literal: true
2
-
3
- $LOAD_PATH << File.expand_path(__dir__)
4
-
5
- module Fleck
6
- module Core
7
- # `Fleck::Core::Consumer` implements the core functionality for `Fleck::Consumer`,
8
- # so that new `Fleck::Consumers` can be easily created by using inheritance.
9
- class Consumer
10
- autoload :Base, 'consumer/base.rb'
11
- autoload :Actions, 'consumer/actions.rb'
12
- autoload :Configuration, 'consumer/configuration.rb'
13
- autoload :Decorators, 'consumer/decorators.rb'
14
- autoload :HelpersDefiners, 'consumer/helpers_definers.rb'
15
- autoload :Logger, 'consumer/logger.rb'
16
-
17
- autoload :Request, 'consumer/request.rb'
18
- autoload :Response, 'consumer/response.rb'
19
-
20
- autoload :ActionHeader, 'consumer/action_header.rb'
21
- autoload :ActionParam, 'consumer/action_param.rb'
22
- autoload :Validation, 'consumer/validation.rb'
23
-
24
- include Fleck::Loggable
25
- include Logger
26
- include Actions
27
- include Configuration
28
- include Decorators
29
- include HelpersDefiners
30
- include Base
31
-
32
- require_relative 'consumer/response_helpers'
33
-
34
- attr_accessor :connection, :channel, :queue, :publisher, :consumer_tag, :request, :subscription, :exchange,
35
- :consumer_id
36
-
37
- def initialize(consumer_id = nil)
38
- self.consumer_id = consumer_id
39
-
40
- instance_eval(&self.class.initialize_block) if self.class.initialize_block
41
-
42
- start if autostart?
43
-
44
- at_exit do
45
- terminate
46
- end
47
- end
48
-
49
- def pause
50
- return if subscription.nil? || channel.nil? || channel.closed?
51
-
52
- cancel_ok = subscription.cancel
53
- self.consumer_tag = cancel_ok.consumer_tag
54
- end
55
-
56
- def resume
57
- subscribe!
58
- end
59
-
60
- def headers
61
- request.headers
62
- end
63
-
64
- def params
65
- request.params
66
- end
67
-
68
- def response
69
- request.response
70
- end
71
-
72
- def deprecated!
73
- logger.warn "DEPRECATION: the method `#{caller_locations(1, 1)[0].label}` is going to be deprecated. " \
74
- 'Please, consider using a newer version of this method.'
75
- response&.deprecated!
76
- end
77
-
78
- protected
79
-
80
- def connect!
81
- self.connection = Fleck.connection(
82
- host: rmq_host,
83
- port: rmq_port,
84
- user: rmq_user,
85
- pass: rmq_pass,
86
- vhost: rmq_vhost
87
- )
88
- end
89
-
90
- def create_channel!
91
- if channel && !channel.closed?
92
- logger.info('Closing the opened channel...')
93
- channel.close
94
- end
95
-
96
- logger.debug "Creating a new channel for #{self.class.to_s.color(:yellow)} consumer"
97
- self.channel = connection.create_channel
98
- channel.prefetch(prefetch_size) # consume messages in batches
99
- self.publisher = Bunny::Exchange.new(connection.create_channel, :direct, 'fleck')
100
- if rmq_exchange_type == :direct && rmq_exchange_name == ''
101
- self.queue = channel.queue(queue_name, auto_delete: false)
102
- else
103
- self.exchange = Bunny::Exchange.new(channel, rmq_exchange_type, rmq_exchange_name)
104
- self.queue = channel.queue('', exclusive: true, auto_delete: true).bind(exchange, routing_key: queue_name)
105
- end
106
- end
107
-
108
- def subscribe!
109
- logger.debug "Consuming from queue: #{queue_name.color(:green)}"
110
-
111
- options = { manual_ack: true }
112
- options[:consumer_tag] = consumer_tag if consumer_tag
113
-
114
- self.subscription = queue.subscribe(options) do |delivery_info, metadata, payload|
115
- process_request!(metadata, payload, delivery_info)
116
- end
117
- end
118
-
119
- def process_request!(metadata, payload, delivery_info)
120
- self.request = Request.new(metadata, payload, delivery_info)
121
-
122
- catch(INTERRUPT_NAME) do
123
- execute_action! unless request.failed?
124
- end
125
- rescue StandardError => e
126
- log_error(e)
127
- internal_server_error! e.inspect, interrupt: false
128
- ensure
129
- send_response!
130
- log_request
131
- end
132
-
133
- def send_response!
134
- return reject_request! if request.rejected?
135
-
136
- logger.debug "Sending response: #{response}"
137
-
138
- if channel.closed?
139
- return logger.warn "Channel already closed! The response #{request.id} is going to be dropped."
140
- end
141
-
142
- publish_response!
143
- request.processed!
144
- end
145
-
146
- def reject_request!
147
- channel.reject(request.delivery_tag, request.requeue?)
148
- end
149
-
150
- def publish_response!
151
- publisher.publish(
152
- response.to_json,
153
- routing_key: request.reply_to,
154
- correlation_id: request.id,
155
- mandatory: ack_mandatory?
156
- )
157
- channel.ack(request.delivery_tag)
158
- end
159
-
160
- def restart!
161
- create_channel!
162
- subscribe!
163
- end
164
- end
165
- end
166
- end
1
+ # frozen_string_literal: true
2
+
3
+ $LOAD_PATH << File.expand_path(__dir__)
4
+
5
+ module Fleck
6
+ module Core
7
+ # `Fleck::Core::Consumer` implements the core functionality for `Fleck::Consumer`,
8
+ # so that new `Fleck::Consumers` can be easily created by using inheritance.
9
+ class Consumer
10
+ autoload :Base, 'consumer/base.rb'
11
+ autoload :Actions, 'consumer/actions.rb'
12
+ autoload :Configuration, 'consumer/configuration.rb'
13
+ autoload :Decorators, 'consumer/decorators.rb'
14
+ autoload :HelpersDefiners, 'consumer/helpers_definers.rb'
15
+ autoload :Logger, 'consumer/logger.rb'
16
+
17
+ autoload :Request, 'consumer/request.rb'
18
+ autoload :Response, 'consumer/response.rb'
19
+
20
+ autoload :ActionHeader, 'consumer/action_header.rb'
21
+ autoload :ActionParam, 'consumer/action_param.rb'
22
+ autoload :Validation, 'consumer/validation.rb'
23
+
24
+ include Fleck::Loggable
25
+ include Logger
26
+ include Actions
27
+ include Configuration
28
+ include Decorators
29
+ include HelpersDefiners
30
+ include Base
31
+
32
+ require_relative 'consumer/response_helpers'
33
+
34
+ attr_accessor :connection, :channel, :queue, :publisher, :consumer_tag, :request, :subscription, :exchange,
35
+ :consumer_id
36
+
37
+ def initialize(consumer_id = nil)
38
+ self.consumer_id = consumer_id
39
+
40
+ instance_eval(&self.class.initialize_block) if self.class.initialize_block
41
+
42
+ start if autostart?
43
+
44
+ at_exit do
45
+ terminate
46
+ end
47
+ end
48
+
49
+ def pause
50
+ return if subscription.nil? || channel.nil? || channel.closed?
51
+
52
+ cancel_ok = subscription.cancel
53
+ self.consumer_tag = cancel_ok.consumer_tag
54
+ end
55
+
56
+ def resume
57
+ subscribe!
58
+ end
59
+
60
+ def headers
61
+ request.headers
62
+ end
63
+
64
+ def params
65
+ request.params
66
+ end
67
+
68
+ def response
69
+ request.response
70
+ end
71
+
72
+ def deprecated!
73
+ logger.warn "DEPRECATION: the method `#{caller_locations(1, 1)[0].label}` is going to be deprecated. " \
74
+ 'Please, consider using a newer version of this method.'
75
+ response&.deprecated!
76
+ end
77
+
78
+ protected
79
+
80
+ def connect!
81
+ self.connection = Fleck.connection(
82
+ host: rmq_host,
83
+ port: rmq_port,
84
+ user: rmq_user,
85
+ pass: rmq_pass,
86
+ vhost: rmq_vhost
87
+ )
88
+ end
89
+
90
+ def create_channel!
91
+ if channel && !channel.closed?
92
+ logger.info('Closing the opened channel...')
93
+ channel.close
94
+ end
95
+
96
+ logger.debug "Creating a new channel for #{self.class.to_s.color(:yellow)} consumer"
97
+ self.channel = connection.create_channel
98
+ channel.prefetch(prefetch_size) # consume messages in batches
99
+ self.publisher = Bunny::Exchange.new(connection.create_channel, :direct, 'fleck')
100
+ if rmq_exchange_type == :direct && rmq_exchange_name == ''
101
+ self.queue = channel.queue(queue_name, auto_delete: false)
102
+ else
103
+ self.exchange = Bunny::Exchange.new(channel, rmq_exchange_type, rmq_exchange_name)
104
+ self.queue = channel.queue('', exclusive: true, auto_delete: true).bind(exchange, routing_key: queue_name)
105
+ end
106
+ end
107
+
108
+ def subscribe!
109
+ logger.debug "Consuming from queue: #{queue_name.color(:green)}"
110
+
111
+ options = { manual_ack: true }
112
+ options[:consumer_tag] = consumer_tag if consumer_tag
113
+
114
+ self.subscription = queue.subscribe(options) do |delivery_info, metadata, payload|
115
+ process_request!(metadata, payload, delivery_info)
116
+ end
117
+ end
118
+
119
+ def process_request!(metadata, payload, delivery_info)
120
+ self.request = Request.new(metadata, payload, delivery_info)
121
+
122
+ catch(INTERRUPT_NAME) do
123
+ execute_action! unless request.failed?
124
+ end
125
+ rescue StandardError => e
126
+ log_error(e)
127
+ internal_server_error! e.inspect, interrupt: false
128
+ ensure
129
+ send_response!
130
+ log_request
131
+ end
132
+
133
+ def send_response!
134
+ return reject_request! if request.rejected?
135
+
136
+ logger.debug "Sending response: #{response}"
137
+
138
+ if channel.closed?
139
+ return logger.warn "Channel already closed! The response #{request.id} is going to be dropped."
140
+ end
141
+
142
+ publish_response!
143
+ request.processed!
144
+ end
145
+
146
+ def reject_request!
147
+ channel.reject(request.delivery_tag, request.requeue?)
148
+ end
149
+
150
+ def publish_response!
151
+ publisher.publish(
152
+ response.to_json,
153
+ routing_key: request.reply_to,
154
+ correlation_id: request.id,
155
+ mandatory: ack_mandatory?
156
+ )
157
+ channel.ack(request.delivery_tag)
158
+ end
159
+
160
+ def restart!
161
+ create_channel!
162
+ subscribe!
163
+ end
164
+ end
165
+ end
166
+ end
data/lib/fleck/core.rb CHANGED
@@ -1,9 +1,9 @@
1
- # frozen_string_literal: true
2
-
3
- $LOAD_PATH << File.expand_path(__dir__)
4
-
5
- module Fleck
6
- module Core
7
- autoload :Consumer, 'core/consumer.rb'
8
- end
9
- end
1
+ # frozen_string_literal: true
2
+
3
+ $LOAD_PATH << File.expand_path(__dir__)
4
+
5
+ module Fleck
6
+ module Core
7
+ autoload :Consumer, 'core/consumer.rb'
8
+ end
9
+ end
@@ -1,80 +1,82 @@
1
- # frozen_string_literal: true
2
-
3
- # `HashWithIndifferentAccess` extends `Hash` class and adds the possibility to access values
4
- # by using both string and symbol keys indifferently.
5
- class HashWithIndifferentAccess < Hash
6
- def initialize(original)
7
- super(nil)
8
- copy_from(original)
9
- end
10
-
11
- def []=(key, value)
12
- super(key.to_s, self.class.convert_value(value))
13
- end
14
-
15
- def [](key)
16
- super(key.to_s)
17
- end
18
-
19
- def fetch(key, *extras)
20
- super(key.to_s, *extras)
21
- end
22
-
23
- def delete(key)
24
- super(key.to_s)
25
- end
26
-
27
- def self.convert_value(value)
28
- case value
29
- when Hash
30
- value.to_hash_with_indifferent_access
31
- when Array
32
- value.map! { |item| item.is_a?(Hash) || item.is_a?(Array) ? HashWithIndifferentAccess.convert_value(item) : item }
33
- else
34
- value
35
- end
36
- end
37
-
38
- protected
39
-
40
- def copy_from(original)
41
- original.each do |key, value|
42
- self[key] = self.class.convert_value(value)
43
- end
44
- end
45
- end
46
-
47
- # Open `Hash` class to add `#to_hash_with_indifferent_access` method and some filter features.
48
- class Hash
49
- def to_hash_with_indifferent_access
50
- HashWithIndifferentAccess.new(self)
51
- end
52
-
53
- def to_s
54
- return dup.filter!.inspect if @filtered
55
-
56
- super
57
- end
58
-
59
- def filtered!
60
- @filtered = true
61
- keys.each do |key|
62
- self[key].filtered! if self[key].is_a?(Hash)
63
- end
64
-
65
- self
66
- end
67
-
68
- def filter!
69
- filters = Fleck.config.filters
70
- keys.each do |key|
71
- if filters.include?(key.to_s)
72
- self[key] = '[FILTERED]'
73
- elsif self[key].is_a?(Hash)
74
- self[key] = self[key].dup.filter!
75
- end
76
- end
77
-
78
- self
79
- end
80
- end
1
+ # frozen_string_literal: true
2
+
3
+ module Fleck
4
+ # `HashWithIndifferentAccess` extends `Hash` class and adds the possibility to access values
5
+ # by using both string and symbol keys indifferently.
6
+ class HashWithIndifferentAccess < Hash
7
+ def initialize(original)
8
+ super(nil)
9
+ copy_from(original)
10
+ end
11
+
12
+ def []=(key, value)
13
+ super(key.to_s, self.class.convert_value(value))
14
+ end
15
+
16
+ def [](key)
17
+ super(key.to_s)
18
+ end
19
+
20
+ def fetch(key, *extras)
21
+ super(key.to_s, *extras)
22
+ end
23
+
24
+ def delete(key)
25
+ super(key.to_s)
26
+ end
27
+
28
+ def self.convert_value(value)
29
+ case value
30
+ when Hash
31
+ value.to_hash_with_indifferent_access
32
+ when Array
33
+ value.map! { |item| item.is_a?(Hash) || item.is_a?(Array) ? Fleck::HashWithIndifferentAccess.convert_value(item) : item }
34
+ else
35
+ value
36
+ end
37
+ end
38
+
39
+ protected
40
+
41
+ def copy_from(original)
42
+ original.each do |key, value|
43
+ self[key] = self.class.convert_value(value)
44
+ end
45
+ end
46
+ end
47
+ end
48
+
49
+ # Open `Hash` class to add `#to_hash_with_indifferent_access` method and some filter features.
50
+ class Hash
51
+ def to_hash_with_indifferent_access
52
+ Fleck::HashWithIndifferentAccess.new(self)
53
+ end
54
+
55
+ def to_s
56
+ return dup.filter!.inspect if @filtered
57
+
58
+ super
59
+ end
60
+
61
+ def filtered!
62
+ @filtered = true
63
+ keys.each do |key|
64
+ self[key].filtered! if self[key].is_a?(Hash)
65
+ end
66
+
67
+ self
68
+ end
69
+
70
+ def filter!
71
+ filters = Fleck.config.filters
72
+ keys.each do |key|
73
+ if filters.include?(key.to_s)
74
+ self[key] = '[FILTERED]'
75
+ elsif self[key].is_a?(Hash)
76
+ self[key] = self[key].dup.filter!
77
+ end
78
+ end
79
+
80
+ self
81
+ end
82
+ end
@@ -64,41 +64,39 @@ module Fleck
64
64
  ensure
65
65
  @updated_at = Time.now
66
66
  end
67
- end
68
67
 
69
- private
68
+ # Use a socket to test connection latency.
69
+ def measure_latency
70
+ socket = create_socket
70
71
 
71
- # Use a socket to test connection latency.
72
- def measure_latency
73
- socket = create_socket
72
+ started_at = Time.now.to_f
73
+ begin
74
+ socket.connect_nonblock(sock_addr)
75
+ rescue IO::WaitWritable
76
+ IO.select(nil, [socket], nil, CONN_TIMEOUT) or raise Timeout::Error
77
+ end
74
78
 
75
- started_at = Time.now.to_f
76
- begin
77
- socket.connect_nonblock(sock_addr)
78
- rescue IO::WaitWritable
79
- IO.select(nil, [socket], nil, CONN_TIMEOUT) or raise Timeout::Error
79
+ (Time.now.to_f - started_at) * 1000 # ms
80
+ ensure
81
+ socket&.close
80
82
  end
81
83
 
82
- (Time.now.to_f - started_at) * 1000 # ms
83
- ensure
84
- socket&.close
85
- end
86
-
87
- # Create a new socket for connection test.
88
- def create_socket
89
- socket = Socket.new(:AF_INET, :SOCK_STREAM, 0)
90
- socket.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
84
+ # Create a new socket for connection test.
85
+ def create_socket
86
+ socket = Socket.new(:AF_INET, :SOCK_STREAM, 0)
87
+ socket.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
91
88
 
92
- socket
93
- end
89
+ socket
90
+ end
94
91
 
95
- # Resolve domain name in order to obtain IP address to test.
96
- def sock_addr
97
- return @sock_addr if @sock_addr
92
+ # Resolve domain name in order to obtain IP address to test.
93
+ def sock_addr
94
+ return @sock_addr if @sock_addr
98
95
 
99
- addr = Socket.getaddrinfo(@host, nil)
100
- @sock_addr = Socket.pack_sockaddr_in(@port, addr[0][3])
96
+ addr = Socket.getaddrinfo(@host, nil)
97
+ @sock_addr = Socket.pack_sockaddr_in(@port, addr[0][3])
101
98
 
102
- @sock_addr
99
+ @sock_addr
100
+ end
103
101
  end
104
102
  end
data/lib/fleck/version.rb CHANGED
@@ -1,6 +1,6 @@
1
- # frozen_string_literal: true
2
-
3
- # Open `Fleck` module to set `VERSION` constant.
4
- module Fleck
5
- VERSION = '2.1.2'
6
- end
1
+ # frozen_string_literal: true
2
+
3
+ # Open `Fleck` module to set `VERSION` constant.
4
+ module Fleck
5
+ VERSION = '2.2.0'
6
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fleck
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.2
4
+ version: 2.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Groza Sergiu
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-02-10 00:00:00.000000000 Z
11
+ date: 2022-12-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -193,7 +193,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
193
193
  - !ruby/object:Gem::Version
194
194
  version: '0'
195
195
  requirements: []
196
- rubygems_version: 3.0.8
196
+ rubygems_version: 3.3.7
197
197
  signing_key:
198
198
  specification_version: 4
199
199
  summary: A Ruby gem for syncronous and asyncronous communication via Message Queue