fleck 2.2.1 → 2.2.3
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.
- checksums.yaml +4 -4
- data/.gitignore +11 -11
- data/Gemfile +6 -6
- data/examples/actions.rb +60 -60
- data/examples/blocking_consumer.rb +42 -42
- data/examples/consumer_initialization.rb +44 -44
- data/examples/deprecation.rb +50 -50
- data/examples/example.rb +76 -76
- data/examples/expired.rb +72 -72
- data/examples/fanout.rb +62 -62
- data/lib/fleck/client.rb +147 -124
- data/lib/fleck/configuration.rb +147 -147
- data/lib/fleck/core/consumer/configuration.rb +69 -69
- data/lib/fleck/core/consumer/helpers_definers.rb +56 -56
- data/lib/fleck/core/consumer/logger.rb +88 -88
- data/lib/fleck/core/consumer/request.rb +100 -100
- data/lib/fleck/core/consumer/response.rb +77 -77
- data/lib/fleck/core/consumer/response_helpers.rb +81 -81
- data/lib/fleck/core/consumer.rb +1 -1
- data/lib/fleck/loggable.rb +15 -15
- data/lib/fleck/utilities/host_rating.rb +102 -102
- data/lib/fleck/version.rb +1 -1
- data/lib/fleck.rb +82 -82
- metadata +2 -2
@@ -1,88 +1,88 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Fleck
|
4
|
-
module Core
|
5
|
-
class Consumer
|
6
|
-
module Logger
|
7
|
-
def self.included(base)
|
8
|
-
base.extend ClassMethods
|
9
|
-
base.send :include, InstanceMethods
|
10
|
-
end
|
11
|
-
|
12
|
-
# Defines class methods to import when `Logger` module is imported.
|
13
|
-
module ClassMethods
|
14
|
-
attr_accessor :logger
|
15
|
-
end
|
16
|
-
|
17
|
-
# Defines instance methods to import when `Logger` module is imported.
|
18
|
-
module InstanceMethods
|
19
|
-
def logger
|
20
|
-
return @logger if @logger
|
21
|
-
|
22
|
-
@logger = self.class.logger.clone
|
23
|
-
@logger.progname = self.class.name.to_s + (configs[:concurrency].to_i <= 1 ? '' : "[#{consumer_id}]")
|
24
|
-
|
25
|
-
@logger
|
26
|
-
end
|
27
|
-
|
28
|
-
private
|
29
|
-
|
30
|
-
def log_request
|
31
|
-
status = final_response_status
|
32
|
-
message = log_formatted_message
|
33
|
-
|
34
|
-
if status >= 500
|
35
|
-
logger.error message
|
36
|
-
elsif status >= 400 || response.deprecated?
|
37
|
-
logger.warn message
|
38
|
-
else
|
39
|
-
logger.info message
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
def exchange_type_code
|
44
|
-
rmq_exchange_type.to_s[0].upcase
|
45
|
-
end
|
46
|
-
|
47
|
-
def final_response_status
|
48
|
-
return 406 if request.rejected?
|
49
|
-
return 503 if channel.closed?
|
50
|
-
|
51
|
-
response.status
|
52
|
-
end
|
53
|
-
|
54
|
-
def log_formatted_message
|
55
|
-
[
|
56
|
-
request_origin,
|
57
|
-
exchange_and_queue_name,
|
58
|
-
request_metadata,
|
59
|
-
request_execution_time,
|
60
|
-
deprecation_message
|
61
|
-
].join
|
62
|
-
end
|
63
|
-
|
64
|
-
def request_origin
|
65
|
-
"#{request.ip} #{request.app_id} => "
|
66
|
-
end
|
67
|
-
|
68
|
-
def exchange_and_queue_name
|
69
|
-
ex_name = rmq_exchange_name.to_s == '' ? ''.inspect : rmq_exchange_name
|
70
|
-
"(#{ex_name}|#{exchange_type_code}|#{queue_name}) "
|
71
|
-
end
|
72
|
-
|
73
|
-
def request_metadata
|
74
|
-
"##{request.id} \"#{request.action} /#{request.version || 'v1'}\" #{final_response_status} "
|
75
|
-
end
|
76
|
-
|
77
|
-
def request_execution_time
|
78
|
-
"(#{request.execution_time}ms)"
|
79
|
-
end
|
80
|
-
|
81
|
-
def deprecation_message
|
82
|
-
response.deprecated? ? ' DEPRECATED' : ''
|
83
|
-
end
|
84
|
-
end
|
85
|
-
end
|
86
|
-
end
|
87
|
-
end
|
88
|
-
end
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Fleck
|
4
|
+
module Core
|
5
|
+
class Consumer
|
6
|
+
module Logger
|
7
|
+
def self.included(base)
|
8
|
+
base.extend ClassMethods
|
9
|
+
base.send :include, InstanceMethods
|
10
|
+
end
|
11
|
+
|
12
|
+
# Defines class methods to import when `Logger` module is imported.
|
13
|
+
module ClassMethods
|
14
|
+
attr_accessor :logger
|
15
|
+
end
|
16
|
+
|
17
|
+
# Defines instance methods to import when `Logger` module is imported.
|
18
|
+
module InstanceMethods
|
19
|
+
def logger
|
20
|
+
return @logger if @logger
|
21
|
+
|
22
|
+
@logger = self.class.logger.clone
|
23
|
+
@logger.progname = self.class.name.to_s + (configs[:concurrency].to_i <= 1 ? '' : "[#{consumer_id}]")
|
24
|
+
|
25
|
+
@logger
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def log_request
|
31
|
+
status = final_response_status
|
32
|
+
message = log_formatted_message
|
33
|
+
|
34
|
+
if status >= 500
|
35
|
+
logger.error message
|
36
|
+
elsif status >= 400 || response.deprecated?
|
37
|
+
logger.warn message
|
38
|
+
else
|
39
|
+
logger.info message
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def exchange_type_code
|
44
|
+
rmq_exchange_type.to_s[0].upcase
|
45
|
+
end
|
46
|
+
|
47
|
+
def final_response_status
|
48
|
+
return 406 if request.rejected?
|
49
|
+
return 503 if channel.closed?
|
50
|
+
|
51
|
+
response.status
|
52
|
+
end
|
53
|
+
|
54
|
+
def log_formatted_message
|
55
|
+
[
|
56
|
+
request_origin,
|
57
|
+
exchange_and_queue_name,
|
58
|
+
request_metadata,
|
59
|
+
request_execution_time,
|
60
|
+
deprecation_message
|
61
|
+
].join
|
62
|
+
end
|
63
|
+
|
64
|
+
def request_origin
|
65
|
+
"#{request.ip} #{request.app_id} => "
|
66
|
+
end
|
67
|
+
|
68
|
+
def exchange_and_queue_name
|
69
|
+
ex_name = rmq_exchange_name.to_s == '' ? ''.inspect : rmq_exchange_name
|
70
|
+
"(#{ex_name}|#{exchange_type_code}|#{queue_name}) "
|
71
|
+
end
|
72
|
+
|
73
|
+
def request_metadata
|
74
|
+
"##{request.id} \"#{request.action} /#{request.version || 'v1'}\" #{final_response_status} "
|
75
|
+
end
|
76
|
+
|
77
|
+
def request_execution_time
|
78
|
+
"(#{request.execution_time}ms)"
|
79
|
+
end
|
80
|
+
|
81
|
+
def deprecation_message
|
82
|
+
response.deprecated? ? ' DEPRECATED' : ''
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -1,100 +1,100 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Fleck
|
4
|
-
module Core
|
5
|
-
class Consumer
|
6
|
-
class Request
|
7
|
-
include Fleck::Loggable
|
8
|
-
|
9
|
-
attr_reader :id, :response, :metadata, :payload, :action, :data, :headers, :version, :ip, :params, :status, :errors,
|
10
|
-
:delivery_tag, :app_id, :reply_to, :created_at, :processed_at
|
11
|
-
|
12
|
-
def initialize(metadata, payload, delivery_info)
|
13
|
-
@created_at = Time.now
|
14
|
-
@id = metadata.correlation_id
|
15
|
-
logger.progname += " #{@id}"
|
16
|
-
|
17
|
-
@response = Fleck::Core::Consumer::Response.new(metadata.correlation_id)
|
18
|
-
@metadata = metadata
|
19
|
-
@app_id = metadata[:app_id]
|
20
|
-
@reply_to = @metadata.reply_to
|
21
|
-
@payload = payload
|
22
|
-
@exchange = delivery_info.exchange
|
23
|
-
@queue = delivery_info.routing_key
|
24
|
-
@delivery_tag = delivery_info.delivery_tag
|
25
|
-
@data = {}
|
26
|
-
@headers = (@metadata.headers || {}).to_hash_with_indifferent_access
|
27
|
-
@action = @metadata.type
|
28
|
-
@version = nil
|
29
|
-
@ip = nil
|
30
|
-
@params = {}
|
31
|
-
@failed = false
|
32
|
-
@rejected = false
|
33
|
-
@requeue = false
|
34
|
-
|
35
|
-
parse_request!
|
36
|
-
end
|
37
|
-
|
38
|
-
def processed!
|
39
|
-
@processed_at = Time.now
|
40
|
-
end
|
41
|
-
|
42
|
-
def execution_time
|
43
|
-
((@processed_at.to_f - @created_at.to_f) * 1000).round(2)
|
44
|
-
end
|
45
|
-
|
46
|
-
def failed?
|
47
|
-
@failed
|
48
|
-
end
|
49
|
-
|
50
|
-
def reject!(requeue: false)
|
51
|
-
@rejected = true
|
52
|
-
@requeue = requeue
|
53
|
-
processed!
|
54
|
-
end
|
55
|
-
|
56
|
-
def rejected?
|
57
|
-
@rejected
|
58
|
-
end
|
59
|
-
|
60
|
-
def requeue?
|
61
|
-
@requeue
|
62
|
-
end
|
63
|
-
|
64
|
-
def log_headers_and_params!
|
65
|
-
queue_name = "(#{@exchange == '' ? @queue : "#{@queue}@#{@exchange}"})".color(:red)
|
66
|
-
endpoint = "/#{action} :#{@version || 'v1'}".color(:red)
|
67
|
-
message = "\n" \
|
68
|
-
"#{ip} - #{queue_name} #{endpoint} [#{@id}]\n" \
|
69
|
-
" ~ headers ~ #{headers.inspect.color(:green)}\n" \
|
70
|
-
" @params #{params.inspect.color(:green)}"
|
71
|
-
logger.debug message
|
72
|
-
end
|
73
|
-
|
74
|
-
protected
|
75
|
-
|
76
|
-
def parse_request!
|
77
|
-
@data = Oj.load(@payload, mode: :compat).to_hash_with_indifferent_access.filtered!
|
78
|
-
@headers.merge!(@data['headers'] || {}).filtered!
|
79
|
-
|
80
|
-
logger.debug "Request (exchange: #{@exchange.inspect}, queue: #{@queue.inspect}, " \
|
81
|
-
"options: #{@headers}, message: #{@data})"
|
82
|
-
|
83
|
-
@action ||= @headers['action']
|
84
|
-
@headers['action'] ||= @action
|
85
|
-
@version = @headers['version']
|
86
|
-
@ip = @headers['ip']
|
87
|
-
@params = @data['params'] || {}
|
88
|
-
rescue Oj::ParseError => e
|
89
|
-
log_error(e)
|
90
|
-
response.render_error(400, 'Bad request', e.inspect)
|
91
|
-
@failed = true
|
92
|
-
rescue StandardError => e
|
93
|
-
log_error(e)
|
94
|
-
response.render_error(500, 'Internal Server Error', e.inspect)
|
95
|
-
@failed = true
|
96
|
-
end
|
97
|
-
end
|
98
|
-
end
|
99
|
-
end
|
100
|
-
end
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Fleck
|
4
|
+
module Core
|
5
|
+
class Consumer
|
6
|
+
class Request
|
7
|
+
include Fleck::Loggable
|
8
|
+
|
9
|
+
attr_reader :id, :response, :metadata, :payload, :action, :data, :headers, :version, :ip, :params, :status, :errors,
|
10
|
+
:delivery_tag, :app_id, :reply_to, :created_at, :processed_at
|
11
|
+
|
12
|
+
def initialize(metadata, payload, delivery_info)
|
13
|
+
@created_at = Time.now
|
14
|
+
@id = metadata.correlation_id
|
15
|
+
logger.progname += " #{@id}"
|
16
|
+
|
17
|
+
@response = Fleck::Core::Consumer::Response.new(metadata.correlation_id)
|
18
|
+
@metadata = metadata
|
19
|
+
@app_id = metadata[:app_id]
|
20
|
+
@reply_to = @metadata.reply_to
|
21
|
+
@payload = payload
|
22
|
+
@exchange = delivery_info.exchange
|
23
|
+
@queue = delivery_info.routing_key
|
24
|
+
@delivery_tag = delivery_info.delivery_tag
|
25
|
+
@data = {}
|
26
|
+
@headers = (@metadata.headers || {}).to_hash_with_indifferent_access
|
27
|
+
@action = @metadata.type
|
28
|
+
@version = nil
|
29
|
+
@ip = nil
|
30
|
+
@params = {}
|
31
|
+
@failed = false
|
32
|
+
@rejected = false
|
33
|
+
@requeue = false
|
34
|
+
|
35
|
+
parse_request!
|
36
|
+
end
|
37
|
+
|
38
|
+
def processed!
|
39
|
+
@processed_at = Time.now
|
40
|
+
end
|
41
|
+
|
42
|
+
def execution_time
|
43
|
+
((@processed_at.to_f - @created_at.to_f) * 1000).round(2)
|
44
|
+
end
|
45
|
+
|
46
|
+
def failed?
|
47
|
+
@failed
|
48
|
+
end
|
49
|
+
|
50
|
+
def reject!(requeue: false)
|
51
|
+
@rejected = true
|
52
|
+
@requeue = requeue
|
53
|
+
processed!
|
54
|
+
end
|
55
|
+
|
56
|
+
def rejected?
|
57
|
+
@rejected
|
58
|
+
end
|
59
|
+
|
60
|
+
def requeue?
|
61
|
+
@requeue
|
62
|
+
end
|
63
|
+
|
64
|
+
def log_headers_and_params!
|
65
|
+
queue_name = "(#{@exchange == '' ? @queue : "#{@queue}@#{@exchange}"})".color(:red)
|
66
|
+
endpoint = "/#{action} :#{@version || 'v1'}".color(:red)
|
67
|
+
message = "\n" \
|
68
|
+
"#{ip} - #{queue_name} #{endpoint} [#{@id}]\n" \
|
69
|
+
" ~ headers ~ #{headers.inspect.color(:green)}\n" \
|
70
|
+
" @params #{params.inspect.color(:green)}"
|
71
|
+
logger.debug message
|
72
|
+
end
|
73
|
+
|
74
|
+
protected
|
75
|
+
|
76
|
+
def parse_request!
|
77
|
+
@data = Oj.load(@payload, mode: :compat).to_hash_with_indifferent_access.filtered!
|
78
|
+
@headers.merge!(@data['headers'] || {}).filtered!
|
79
|
+
|
80
|
+
logger.debug "Request (exchange: #{@exchange.inspect}, queue: #{@queue.inspect}, " \
|
81
|
+
"options: #{@headers}, message: #{@data})"
|
82
|
+
|
83
|
+
@action ||= @headers['action']
|
84
|
+
@headers['action'] ||= @action
|
85
|
+
@version = @headers['version']
|
86
|
+
@ip = @headers['ip']
|
87
|
+
@params = @data['params'] || {}
|
88
|
+
rescue Oj::ParseError => e
|
89
|
+
log_error(e)
|
90
|
+
response.render_error(400, 'Bad request', e.inspect)
|
91
|
+
@failed = true
|
92
|
+
rescue StandardError => e
|
93
|
+
log_error(e)
|
94
|
+
response.render_error(500, 'Internal Server Error', e.inspect)
|
95
|
+
@failed = true
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -1,77 +1,77 @@
|
|
1
|
-
|
2
|
-
module Fleck
|
3
|
-
module Core
|
4
|
-
class Consumer
|
5
|
-
class Response
|
6
|
-
include Fleck::Loggable
|
7
|
-
|
8
|
-
attr_accessor :id, :status, :errors, :headers, :body
|
9
|
-
|
10
|
-
def initialize(request_id)
|
11
|
-
@id = request_id
|
12
|
-
logger.progname += " #{@id}"
|
13
|
-
|
14
|
-
@status = 200
|
15
|
-
@errors = []
|
16
|
-
@headers = {}
|
17
|
-
@body = nil
|
18
|
-
@deprecated = false
|
19
|
-
end
|
20
|
-
|
21
|
-
def errors?
|
22
|
-
!@errors.empty?
|
23
|
-
end
|
24
|
-
|
25
|
-
def deprecated!
|
26
|
-
@deprecated = true
|
27
|
-
end
|
28
|
-
|
29
|
-
def deprecated?
|
30
|
-
@deprecated
|
31
|
-
end
|
32
|
-
|
33
|
-
def not_found(msg = nil)
|
34
|
-
@status = 404
|
35
|
-
@errors << 'Resource Not Found'
|
36
|
-
@errors << msg if msg
|
37
|
-
end
|
38
|
-
|
39
|
-
def render_error(status, msg = [])
|
40
|
-
raise ArgumentError, "Invalid status code: #{status.inspect}" unless (400..599).cover?(status.to_i)
|
41
|
-
|
42
|
-
@status = status.to_i
|
43
|
-
if msg.is_a?(Array)
|
44
|
-
@errors += msg
|
45
|
-
else
|
46
|
-
@errors << msg
|
47
|
-
end
|
48
|
-
|
49
|
-
@errors.compact!
|
50
|
-
end
|
51
|
-
|
52
|
-
def to_json(filter: false)
|
53
|
-
data = {
|
54
|
-
"status" => @status,
|
55
|
-
"errors" => @errors,
|
56
|
-
"headers" => @headers,
|
57
|
-
"body" => @body,
|
58
|
-
"deprecated" => @deprecated
|
59
|
-
}
|
60
|
-
data.filter! if filter
|
61
|
-
|
62
|
-
return Oj.dump(data, mode: :compat)
|
63
|
-
rescue => e
|
64
|
-
logger.error e.inspect + "\n" + e.backtrace.join("\n")
|
65
|
-
return Oj.dump({
|
66
|
-
"status" => 500,
|
67
|
-
"errors" => ['Internal Server Error', 'Failed to dump the response to JSON']
|
68
|
-
}, mode: :compat)
|
69
|
-
end
|
70
|
-
|
71
|
-
def to_s
|
72
|
-
return "#<#{self.class} #{self.to_json(filter: true)}>"
|
73
|
-
end
|
74
|
-
end
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end
|
1
|
+
|
2
|
+
module Fleck
|
3
|
+
module Core
|
4
|
+
class Consumer
|
5
|
+
class Response
|
6
|
+
include Fleck::Loggable
|
7
|
+
|
8
|
+
attr_accessor :id, :status, :errors, :headers, :body
|
9
|
+
|
10
|
+
def initialize(request_id)
|
11
|
+
@id = request_id
|
12
|
+
logger.progname += " #{@id}"
|
13
|
+
|
14
|
+
@status = 200
|
15
|
+
@errors = []
|
16
|
+
@headers = {}
|
17
|
+
@body = nil
|
18
|
+
@deprecated = false
|
19
|
+
end
|
20
|
+
|
21
|
+
def errors?
|
22
|
+
!@errors.empty?
|
23
|
+
end
|
24
|
+
|
25
|
+
def deprecated!
|
26
|
+
@deprecated = true
|
27
|
+
end
|
28
|
+
|
29
|
+
def deprecated?
|
30
|
+
@deprecated
|
31
|
+
end
|
32
|
+
|
33
|
+
def not_found(msg = nil)
|
34
|
+
@status = 404
|
35
|
+
@errors << 'Resource Not Found'
|
36
|
+
@errors << msg if msg
|
37
|
+
end
|
38
|
+
|
39
|
+
def render_error(status, msg = [])
|
40
|
+
raise ArgumentError, "Invalid status code: #{status.inspect}" unless (400..599).cover?(status.to_i)
|
41
|
+
|
42
|
+
@status = status.to_i
|
43
|
+
if msg.is_a?(Array)
|
44
|
+
@errors += msg
|
45
|
+
else
|
46
|
+
@errors << msg
|
47
|
+
end
|
48
|
+
|
49
|
+
@errors.compact!
|
50
|
+
end
|
51
|
+
|
52
|
+
def to_json(filter: false)
|
53
|
+
data = {
|
54
|
+
"status" => @status,
|
55
|
+
"errors" => @errors,
|
56
|
+
"headers" => @headers,
|
57
|
+
"body" => @body,
|
58
|
+
"deprecated" => @deprecated
|
59
|
+
}
|
60
|
+
data.filter! if filter
|
61
|
+
|
62
|
+
return Oj.dump(data, mode: :compat)
|
63
|
+
rescue => e
|
64
|
+
logger.error e.inspect + "\n" + e.backtrace.join("\n")
|
65
|
+
return Oj.dump({
|
66
|
+
"status" => 500,
|
67
|
+
"errors" => ['Internal Server Error', 'Failed to dump the response to JSON']
|
68
|
+
}, mode: :compat)
|
69
|
+
end
|
70
|
+
|
71
|
+
def to_s
|
72
|
+
return "#<#{self.class} #{self.to_json(filter: true)}>"
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|