fleck 1.0.1 → 2.0.0
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 -10
- data/CHANGELOG.md +89 -74
- data/Gemfile +6 -4
- data/examples/actions.rb +59 -53
- data/examples/blocking_consumer.rb +42 -42
- data/examples/consumer_initialization.rb +44 -42
- data/examples/deprecation.rb +50 -57
- data/examples/example.rb +76 -74
- data/examples/expired.rb +72 -76
- data/examples/fanout.rb +62 -64
- data/fleck.gemspec +37 -36
- data/lib/fleck/client.rb +124 -124
- data/lib/fleck/configuration.rb +149 -144
- data/lib/fleck/consumer.rb +7 -287
- data/lib/fleck/core/consumer/action_param.rb +106 -0
- data/lib/fleck/core/consumer/actions.rb +76 -0
- data/lib/fleck/core/consumer/base.rb +111 -0
- data/lib/fleck/core/consumer/configuration.rb +69 -0
- data/lib/fleck/core/consumer/decorators.rb +77 -0
- data/lib/fleck/core/consumer/helpers_definers.rb +55 -0
- data/lib/fleck/core/consumer/logger.rb +88 -0
- data/lib/fleck/core/consumer/request.rb +89 -0
- data/lib/fleck/core/consumer/response.rb +77 -0
- data/lib/fleck/core/consumer/response_helpers.rb +81 -0
- data/lib/fleck/core/consumer/validation.rb +163 -0
- data/lib/fleck/core/consumer.rb +166 -0
- data/lib/fleck/core.rb +9 -0
- data/lib/fleck/loggable.rb +15 -10
- data/lib/fleck/{hash_with_indifferent_access.rb → utilities/hash_with_indifferent_access.rb} +80 -85
- data/lib/fleck/utilities/host_rating.rb +104 -0
- data/lib/fleck/version.rb +6 -3
- data/lib/fleck.rb +81 -72
- metadata +35 -24
- data/lib/fleck/consumer/request.rb +0 -52
- data/lib/fleck/consumer/response.rb +0 -80
- data/lib/fleck/host_rating.rb +0 -74
data/lib/fleck/client.rb
CHANGED
@@ -1,124 +1,124 @@
|
|
1
|
-
|
2
|
-
module Fleck
|
3
|
-
class Client
|
4
|
-
include Fleck::Loggable
|
5
|
-
|
6
|
-
attr_reader :local_ip, :remote_ip
|
7
|
-
|
8
|
-
def initialize(connection, queue_name = "", exchange_type: :direct, exchange_name: "", multiple_responses: false, concurrency: 1)
|
9
|
-
@connection = connection
|
10
|
-
@queue_name = queue_name
|
11
|
-
@multiple_responses = multiple_responses
|
12
|
-
@default_timeout = multiple_responses ? 60 : nil
|
13
|
-
@concurrency = [concurrency.to_i, 1].max
|
14
|
-
@requests = ThreadSafe::Hash.new
|
15
|
-
@subscriptions = ThreadSafe::Array.new
|
16
|
-
@terminated = false
|
17
|
-
@mutex = Mutex.new
|
18
|
-
@local_ip = @connection.transport.socket.local_address.ip_address
|
19
|
-
@remote_ip = @connection.transport.socket.remote_address.ip_address
|
20
|
-
|
21
|
-
@channel = @connection.create_channel
|
22
|
-
@exchange = Bunny::Exchange.new(@channel, :direct, 'fleck')
|
23
|
-
@publisher = Bunny::Exchange.new(@connection.create_channel, exchange_type, exchange_name)
|
24
|
-
@reply_queue = @channel.queue("", exclusive: true, auto_delete: true)
|
25
|
-
@reply_queue.bind(@exchange, routing_key: @reply_queue.name)
|
26
|
-
|
27
|
-
handle_returned_messages!
|
28
|
-
@concurrency.times { handle_responses! }
|
29
|
-
|
30
|
-
logger.debug("Client initialized!")
|
31
|
-
|
32
|
-
at_exit do
|
33
|
-
terminate
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
def request(action: nil, version: nil, headers: {}, params: {}, async: @multiple_responses || false, timeout: @default_timeout, queue: @queue_name, rmq_options: {}, &block)
|
38
|
-
|
39
|
-
if @terminated
|
40
|
-
return Fleck::Client::Response.new(Oj.dump({status: 503, errors: ['Service Unavailable'], body: nil} , mode: :compat))
|
41
|
-
end
|
42
|
-
|
43
|
-
request = Fleck::Client::Request.new(
|
44
|
-
self, queue, @reply_queue.name,
|
45
|
-
action: action,
|
46
|
-
version: version,
|
47
|
-
headers: headers,
|
48
|
-
params: params,
|
49
|
-
timeout: timeout,
|
50
|
-
multiple_responses: @multiple_responses,
|
51
|
-
rmq_options: rmq_options,
|
52
|
-
&block
|
53
|
-
)
|
54
|
-
|
55
|
-
@requests[request.id] = request
|
56
|
-
request.send!(async)
|
57
|
-
|
58
|
-
return request.response
|
59
|
-
end
|
60
|
-
|
61
|
-
|
62
|
-
def publish(data, options)
|
63
|
-
return if @terminated
|
64
|
-
@mutex.synchronize { @publisher.publish(data, options) }
|
65
|
-
end
|
66
|
-
|
67
|
-
|
68
|
-
def remove_request(request_id)
|
69
|
-
@requests.delete request_id
|
70
|
-
end
|
71
|
-
|
72
|
-
|
73
|
-
def terminate
|
74
|
-
@terminated = true
|
75
|
-
logger.info "Unsubscribing from #{@reply_queue.name}"
|
76
|
-
@subscriptions.map(&:cancel) # stop receiving new messages
|
77
|
-
logger.info "Canceling pending requests"
|
78
|
-
# cancel pending requests
|
79
|
-
while item = @requests.shift do
|
80
|
-
begin
|
81
|
-
item[1].cancel!
|
82
|
-
rescue => e
|
83
|
-
logger.error e.inspect + "\n" + e.backtrace.join("\n")
|
84
|
-
end
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
|
-
|
89
|
-
protected
|
90
|
-
|
91
|
-
def handle_returned_messages!
|
92
|
-
@exchange.on_return do |return_info, metadata, content|
|
93
|
-
begin
|
94
|
-
logger.warn "Request #{metadata[:correlation_id]} returned"
|
95
|
-
request = @requests[metadata[:correlation_id]]
|
96
|
-
if request
|
97
|
-
request.cancel!
|
98
|
-
end
|
99
|
-
rescue => e
|
100
|
-
logger.error e.inspect + "\n" + e.backtrace.join("\n")
|
101
|
-
end
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
|
-
def handle_responses!
|
106
|
-
@subscriptions << @reply_queue.subscribe do |delivery_info, metadata, payload|
|
107
|
-
begin
|
108
|
-
logger.debug "Response received: #{payload}"
|
109
|
-
request = @requests[metadata[:correlation_id]]
|
110
|
-
if request
|
111
|
-
request.response = Fleck::Client::Response.new(payload)
|
112
|
-
else
|
113
|
-
logger.warn "Request #{metadata[:correlation_id]} not found!"
|
114
|
-
end
|
115
|
-
rescue => e
|
116
|
-
logger.error e.inspect + "\n" + e.backtrace.join("\n")
|
117
|
-
end
|
118
|
-
end
|
119
|
-
end
|
120
|
-
end
|
121
|
-
end
|
122
|
-
|
123
|
-
require "fleck/client/request"
|
124
|
-
require "fleck/client/response"
|
1
|
+
|
2
|
+
module Fleck
|
3
|
+
class Client
|
4
|
+
include Fleck::Loggable
|
5
|
+
|
6
|
+
attr_reader :local_ip, :remote_ip
|
7
|
+
|
8
|
+
def initialize(connection, queue_name = "", exchange_type: :direct, exchange_name: "", multiple_responses: false, concurrency: 1)
|
9
|
+
@connection = connection
|
10
|
+
@queue_name = queue_name
|
11
|
+
@multiple_responses = multiple_responses
|
12
|
+
@default_timeout = multiple_responses ? 60 : nil
|
13
|
+
@concurrency = [concurrency.to_i, 1].max
|
14
|
+
@requests = ThreadSafe::Hash.new
|
15
|
+
@subscriptions = ThreadSafe::Array.new
|
16
|
+
@terminated = false
|
17
|
+
@mutex = Mutex.new
|
18
|
+
@local_ip = @connection.transport.socket.local_address.ip_address
|
19
|
+
@remote_ip = @connection.transport.socket.remote_address.ip_address
|
20
|
+
|
21
|
+
@channel = @connection.create_channel
|
22
|
+
@exchange = Bunny::Exchange.new(@channel, :direct, 'fleck')
|
23
|
+
@publisher = Bunny::Exchange.new(@connection.create_channel, exchange_type, exchange_name)
|
24
|
+
@reply_queue = @channel.queue("", exclusive: true, auto_delete: true)
|
25
|
+
@reply_queue.bind(@exchange, routing_key: @reply_queue.name)
|
26
|
+
|
27
|
+
handle_returned_messages!
|
28
|
+
@concurrency.times { handle_responses! }
|
29
|
+
|
30
|
+
logger.debug("Client initialized!")
|
31
|
+
|
32
|
+
at_exit do
|
33
|
+
terminate
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def request(action: nil, version: nil, headers: {}, params: {}, async: @multiple_responses || false, timeout: @default_timeout, queue: @queue_name, rmq_options: {}, &block)
|
38
|
+
|
39
|
+
if @terminated
|
40
|
+
return Fleck::Client::Response.new(Oj.dump({status: 503, errors: ['Service Unavailable'], body: nil} , mode: :compat))
|
41
|
+
end
|
42
|
+
|
43
|
+
request = Fleck::Client::Request.new(
|
44
|
+
self, queue, @reply_queue.name,
|
45
|
+
action: action,
|
46
|
+
version: version,
|
47
|
+
headers: headers,
|
48
|
+
params: params,
|
49
|
+
timeout: timeout,
|
50
|
+
multiple_responses: @multiple_responses,
|
51
|
+
rmq_options: rmq_options,
|
52
|
+
&block
|
53
|
+
)
|
54
|
+
|
55
|
+
@requests[request.id] = request
|
56
|
+
request.send!(async)
|
57
|
+
|
58
|
+
return request.response
|
59
|
+
end
|
60
|
+
|
61
|
+
|
62
|
+
def publish(data, options)
|
63
|
+
return if @terminated
|
64
|
+
@mutex.synchronize { @publisher.publish(data, options) }
|
65
|
+
end
|
66
|
+
|
67
|
+
|
68
|
+
def remove_request(request_id)
|
69
|
+
@requests.delete request_id
|
70
|
+
end
|
71
|
+
|
72
|
+
|
73
|
+
def terminate
|
74
|
+
@terminated = true
|
75
|
+
logger.info "Unsubscribing from #{@reply_queue.name}"
|
76
|
+
@subscriptions.map(&:cancel) # stop receiving new messages
|
77
|
+
logger.info "Canceling pending requests"
|
78
|
+
# cancel pending requests
|
79
|
+
while item = @requests.shift do
|
80
|
+
begin
|
81
|
+
item[1].cancel!
|
82
|
+
rescue => e
|
83
|
+
logger.error e.inspect + "\n" + e.backtrace.join("\n")
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
|
89
|
+
protected
|
90
|
+
|
91
|
+
def handle_returned_messages!
|
92
|
+
@exchange.on_return do |return_info, metadata, content|
|
93
|
+
begin
|
94
|
+
logger.warn "Request #{metadata[:correlation_id]} returned"
|
95
|
+
request = @requests[metadata[:correlation_id]]
|
96
|
+
if request
|
97
|
+
request.cancel!
|
98
|
+
end
|
99
|
+
rescue => e
|
100
|
+
logger.error e.inspect + "\n" + e.backtrace.join("\n")
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def handle_responses!
|
106
|
+
@subscriptions << @reply_queue.subscribe do |delivery_info, metadata, payload|
|
107
|
+
begin
|
108
|
+
logger.debug "Response received: #{payload}"
|
109
|
+
request = @requests[metadata[:correlation_id]]
|
110
|
+
if request
|
111
|
+
request.response = Fleck::Client::Response.new(payload)
|
112
|
+
else
|
113
|
+
logger.warn "Request #{metadata[:correlation_id]} not found!"
|
114
|
+
end
|
115
|
+
rescue => e
|
116
|
+
logger.error e.inspect + "\n" + e.backtrace.join("\n")
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
require "fleck/client/request"
|
124
|
+
require "fleck/client/response"
|
data/lib/fleck/configuration.rb
CHANGED
@@ -1,144 +1,149 @@
|
|
1
|
-
|
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
|
-
host
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
opts[:
|
58
|
-
|
59
|
-
opts
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
end
|
82
|
-
|
83
|
-
def
|
84
|
-
@
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Open `Fleck` module to add `Configuration` class implementation.
|
4
|
+
module Fleck
|
5
|
+
# `Fleck::Configuration` implements a set of methods useful for `Fleck` clients and consumers configuration.
|
6
|
+
class Configuration
|
7
|
+
autoload :HostRating, 'fleck/utilities/host_rating.rb'
|
8
|
+
|
9
|
+
attr_reader :logfile, :loglevel, :progname, :hosts
|
10
|
+
attr_accessor :default_user, :default_pass, :default_host, :default_port, :default_vhost, :default_queue,
|
11
|
+
:app_name, :filters
|
12
|
+
|
13
|
+
def initialize
|
14
|
+
@logfile = $stdout
|
15
|
+
@loglevel = ::Logger::INFO
|
16
|
+
@progname = 'Fleck'
|
17
|
+
@app_name = $PROGRAM_NAME
|
18
|
+
@default_host = '127.0.0.1'
|
19
|
+
@default_port = 5672
|
20
|
+
@default_user = nil
|
21
|
+
@default_pass = nil
|
22
|
+
@default_vhost = '/'
|
23
|
+
@default_queue = 'default'
|
24
|
+
@filters = %w[password secret token]
|
25
|
+
@hosts = []
|
26
|
+
@credentials = {}
|
27
|
+
end
|
28
|
+
|
29
|
+
def hosts=(*args)
|
30
|
+
args.flatten.each do |host|
|
31
|
+
add_host host
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def add_host(data)
|
36
|
+
case data
|
37
|
+
when String then add_host_from_string(data)
|
38
|
+
when Hash then add_host_from_hash(data)
|
39
|
+
else
|
40
|
+
raise ArgumentError, "Invalid host type #{data.inspect}: String or Hash expected"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def default_options
|
45
|
+
best = @hosts.min
|
46
|
+
opts = {}
|
47
|
+
|
48
|
+
host = best ? best.host : @default_host
|
49
|
+
port = best ? best.port : @default_port
|
50
|
+
credentials = @credentials["#{host}:#{port}"] || { user: @default_user, pass: @default_pass }
|
51
|
+
|
52
|
+
opts[:host] = host
|
53
|
+
opts[:port] = port
|
54
|
+
opts[:user] = credentials[:user] || @default_user
|
55
|
+
opts[:pass] = credentials[:pass] || @default_pass
|
56
|
+
opts[:vhost] = @default_vhost
|
57
|
+
opts[:queue] = @default_queue
|
58
|
+
|
59
|
+
opts
|
60
|
+
end
|
61
|
+
|
62
|
+
def logfile=(new_logfile)
|
63
|
+
return unless @logfile != new_logfile
|
64
|
+
|
65
|
+
@logfile = new_logfile
|
66
|
+
reset_logger
|
67
|
+
end
|
68
|
+
|
69
|
+
def loglevel=(new_loglevel)
|
70
|
+
@loglevel = new_loglevel
|
71
|
+
@logger.level = @loglevel if @logger
|
72
|
+
end
|
73
|
+
|
74
|
+
def progname=(new_progname)
|
75
|
+
@progname = new_progname
|
76
|
+
@logger.progname = @progname if @logger
|
77
|
+
end
|
78
|
+
|
79
|
+
def logger
|
80
|
+
@logger || reset_logger
|
81
|
+
end
|
82
|
+
|
83
|
+
def logger=(new_logger)
|
84
|
+
@logger&.close
|
85
|
+
|
86
|
+
if new_logger.nil?
|
87
|
+
@logger = ::Logger.new(nil)
|
88
|
+
else
|
89
|
+
@logger = new_logger.clone
|
90
|
+
@logger.formatter = formatter
|
91
|
+
@logger.progname = @progname
|
92
|
+
@logger.level = @loglevel
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def reset_logger
|
97
|
+
new_logger = ::Logger.new(@logfile)
|
98
|
+
new_logger.formatter = formatter
|
99
|
+
new_logger.progname = @progname
|
100
|
+
new_logger.level = @loglevel
|
101
|
+
@logger&.close
|
102
|
+
@logger = new_logger
|
103
|
+
|
104
|
+
@logger
|
105
|
+
end
|
106
|
+
|
107
|
+
def formatter
|
108
|
+
return @formatter if @formatter
|
109
|
+
|
110
|
+
@formatter = proc do |severity, datetime, progname, msg|
|
111
|
+
color = severity_color(severity)
|
112
|
+
"[#{datetime.strftime('%F %T.%L')}]".color(:cyan) +
|
113
|
+
"(#{$PID})".color(:blue) +
|
114
|
+
"|#{severity}|".color(color) +
|
115
|
+
(progname ? "<#{progname}>".color(:yellow) : '') +
|
116
|
+
" #{msg}\n"
|
117
|
+
end
|
118
|
+
|
119
|
+
@formatter
|
120
|
+
end
|
121
|
+
|
122
|
+
private
|
123
|
+
|
124
|
+
def add_host_from_string(data)
|
125
|
+
host, port = data.split(':')
|
126
|
+
port = port ? port.to_i : 5672
|
127
|
+
@hosts << Fleck::HostRating.new(host: host, port: port)
|
128
|
+
@credentials["#{host}:#{port}"] ||= { user: @default_user, pass: @default_pass }
|
129
|
+
end
|
130
|
+
|
131
|
+
def add_host_from_hash(data)
|
132
|
+
data = data.to_hash_with_indifferent_access
|
133
|
+
host = data[:host] || @default_host
|
134
|
+
port = data[:port] || @default_port
|
135
|
+
@hosts << Fleck::HostRating.new(host: host, port: port)
|
136
|
+
@credentials["#{host}:#{port}"] ||= { user: data[:user] || @default_user, pass: data[:pass] || @default_pass }
|
137
|
+
end
|
138
|
+
|
139
|
+
def severity_color(severity)
|
140
|
+
case severity
|
141
|
+
when 'DEBUG' then '#512DA8'
|
142
|
+
when 'INFO' then '#33691E'
|
143
|
+
when 'WARN' then '#E65100'
|
144
|
+
when 'ERROR', 'FATAL' then '#B71C1C'
|
145
|
+
else '#00BCD4'
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|