fleck 2.1.3 → 2.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +40 -10
- data/fleck.gemspec +37 -37
- data/lib/fleck/consumer.rb +7 -7
- data/lib/fleck/core/consumer/action_param.rb +12 -4
- data/lib/fleck/core/consumer/base.rb +111 -111
- data/lib/fleck/core/consumer/decorators.rb +3 -3
- data/lib/fleck/core/consumer/validation.rb +11 -2
- data/lib/fleck/core/consumer.rb +166 -166
- data/lib/fleck/core.rb +9 -9
- data/lib/fleck/utilities/hash_with_indifferent_access.rb +82 -80
- data/lib/fleck/version.rb +6 -6
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 469551dc2d0172cea61bba8b982d70a6f8b68258f956c359602f02487490a77c
|
4
|
+
data.tar.gz: e2c0999b1da9cbf39246dd70dbeb3fcdec98072779a5bcc124ec4313c8a8e762
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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**
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
data/lib/fleck/consumer.rb
CHANGED
@@ -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,
|
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,
|
53
|
-
method_options[:params][name] = ActionParam.new(name,
|
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,
|
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,
|
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
|
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
|
data/lib/fleck/core/consumer.rb
CHANGED
@@ -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
|
-
|
4
|
-
#
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
original
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
end
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
self[key] =
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
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
|
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.
|
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.
|
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-
|
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.
|
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
|