smith 0.5.13.1 → 0.6.1
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 +7 -0
- data/bin/agency +19 -7
- data/bin/pry-smith +11 -0
- data/bin/smithctl +19 -21
- data/lib/smith/acl_compiler.rb +101 -56
- data/lib/smith/acl_parser.rb +75 -0
- data/lib/smith/agent.rb +28 -43
- data/lib/smith/agent_cache.rb +43 -17
- data/lib/smith/agent_monitoring.rb +1 -1
- data/lib/smith/agent_process.rb +148 -53
- data/lib/smith/application/agency.rb +44 -54
- data/lib/smith/bootstrap.rb +31 -17
- data/lib/smith/cache.rb +4 -0
- data/lib/smith/command.rb +1 -3
- data/lib/smith/commands/agency/kill.rb +22 -5
- data/lib/smith/commands/agency/list.rb +9 -4
- data/lib/smith/commands/agency/logger.rb +25 -12
- data/lib/smith/commands/agency/object_count.rb +19 -8
- data/lib/smith/commands/agency/start.rb +7 -10
- data/lib/smith/commands/agency/stop.rb +30 -12
- data/lib/smith/commands/common.rb +1 -1
- data/lib/smith/commands/smithctl/acl.rb +6 -3
- data/lib/smith/commands/smithctl/dump.rb +79 -0
- data/lib/smith/commands/smithctl/firehose.rb +2 -1
- data/lib/smith/commands/smithctl/push.rb +27 -12
- data/lib/smith/commands/smithctl/status.rb +27 -0
- data/lib/smith/config.rb +140 -28
- data/lib/smith/daemon.rb +16 -3
- data/lib/smith/exceptions.rb +6 -3
- data/lib/smith/logger.rb +12 -24
- data/lib/smith/messaging/acl/agent_keepalive.proto +2 -2
- data/lib/smith/messaging/acl/agent_lifecycle.proto +15 -9
- data/lib/smith/messaging/acl/agent_stats.proto +6 -5
- data/lib/smith/messaging/acl/default.rb +2 -7
- data/lib/smith/messaging/acl_type_cache.rb +77 -0
- data/lib/smith/messaging/factory.rb +29 -0
- data/lib/smith/messaging/queue.rb +12 -10
- data/lib/smith/messaging/queue_definition.rb +21 -4
- data/lib/smith/messaging/receiver.rb +55 -62
- data/lib/smith/messaging/requeue.rb +1 -5
- data/lib/smith/messaging/sender.rb +48 -43
- data/lib/smith/messaging/util.rb +0 -10
- data/lib/smith/queue_definitions.rb +7 -4
- data/lib/smith/version.rb +1 -1
- data/lib/smith.rb +57 -56
- metadata +77 -128
- data/lib/smith/messaging/payload.rb +0 -100
@@ -7,20 +7,19 @@ module Smith
|
|
7
7
|
include Logger
|
8
8
|
include Util
|
9
9
|
|
10
|
-
|
10
|
+
def initialize(queue_def, opts={}, &blk)
|
11
11
|
|
12
|
-
|
12
|
+
# This is for backward compatibility.
|
13
|
+
@queue_def = queue_def.is_a?(QueueDefinition) ? queue_def : QueueDefinition.new(queue_def, opts)
|
13
14
|
|
14
|
-
@
|
15
|
+
@acl_type_cache = AclTypeCache.instance
|
15
16
|
|
16
17
|
@reply_container = {}
|
17
18
|
|
18
|
-
|
19
|
+
prefetch = option_or_default(@queue_def.options, :prefetch, Smith.config.agent.prefetch)
|
19
20
|
|
20
|
-
|
21
|
-
|
22
|
-
@options = AmqpOptions.new(opts)
|
23
|
-
@options.routing_key = normalised_queue_name
|
21
|
+
@options = AmqpOptions.new(@queue_def.options)
|
22
|
+
@options.routing_key = @queue_def.normalise
|
24
23
|
|
25
24
|
@message_counts = Hash.new(0)
|
26
25
|
|
@@ -30,15 +29,15 @@ module Smith
|
|
30
29
|
|
31
30
|
open_channel(:prefetch => prefetch) do |channel|
|
32
31
|
@channel_completion.succeed(channel)
|
33
|
-
channel.direct(
|
32
|
+
channel.direct(@queue_def.normalise, @options.exchange) do |exchange|
|
34
33
|
|
35
34
|
exchange.on_return do |basic_return,metadata,payload|
|
36
|
-
logger.error { "#{
|
35
|
+
logger.error { "#{@acl_type_cache[metadata.type].new.parse_from_string} returned! Exchange: #{reply_code.exchange}, reply_code: #{basic_return.reply_code}, reply_text: #{basic_return.reply_text}" }
|
37
36
|
logger.error { "Properties: #{metadata.properties}" }
|
38
37
|
end
|
39
38
|
|
40
|
-
channel.queue(
|
41
|
-
queue.bind(exchange, :routing_key =>
|
39
|
+
channel.queue(@queue_def.normalise, @options.queue) do |queue|
|
40
|
+
queue.bind(exchange, :routing_key => @queue_def.normalise)
|
42
41
|
|
43
42
|
@queue_completion.succeed(queue)
|
44
43
|
@exchange_completion.succeed(exchange)
|
@@ -64,47 +63,46 @@ module Smith
|
|
64
63
|
message_id = random
|
65
64
|
logger.verbose { "message_id: #{message_id}" }
|
66
65
|
|
67
|
-
####
|
68
|
-
#### TODO if there is a timeout delete
|
69
|
-
|
70
|
-
####
|
66
|
+
#### !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ####
|
67
|
+
#### TODO if there is a timeout delete ####
|
68
|
+
#### the proc from the @reply_container. ####
|
69
|
+
#### !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ####
|
71
70
|
@reply_container[message_id] = {:reply_proc => @reply_proc, :timeout => @timeout.clone.tap {|t| t.set_timeout(message_id) }}
|
72
|
-
_publish(
|
71
|
+
_publish(payload, @options.publish(opts, {:reply_to => reply_queue.queue_name, :message_id => message_id}))
|
73
72
|
end
|
74
73
|
else
|
75
|
-
_publish(
|
74
|
+
_publish(payload, @options.publish(opts), &blk)
|
76
75
|
end
|
77
76
|
end
|
78
77
|
|
79
|
-
def on_timeout(timeout, &blk)
|
80
|
-
@timeout = Timeout.new(timeout, &blk)
|
78
|
+
def on_timeout(timeout=nil, &blk)
|
79
|
+
@timeout = Timeout.new(timeout || Smith.config.smith.timeout, &blk)
|
81
80
|
end
|
82
81
|
|
83
82
|
# Set up a listener that will receive replies from the published
|
84
83
|
# messages. You must publish with intent to reply -- tee he.
|
85
84
|
#
|
86
85
|
# If you pass in a queue_name the same queue name will get used for every
|
87
|
-
# reply. This means that there are no create and teardown costs for
|
88
|
-
#
|
89
|
-
# assigned.
|
86
|
+
# reply. This means that there are no create and teardown costs for each
|
87
|
+
# message. If no queue_name is given a random one will be assigned.
|
90
88
|
def on_reply(opts={}, &blk)
|
91
89
|
@reply_proc = blk
|
92
|
-
@timeout ||= Timeout.new(Smith.config.agency.timeout, :queue_name => @queue_name)
|
93
|
-
reply_queue_name = opts.delete(:reply_queue_name) || random
|
94
90
|
|
95
|
-
|
91
|
+
@timeout ||= Timeout.new(Smith.config.smith.timeout, :queue_name => @queue_def.denormalise)
|
96
92
|
|
97
|
-
|
93
|
+
queue_def = QueueDefinition.new(opts.delete(:reply_queue_name) || "#{@queue_def.denormalise}.reply", opts.merge(:auto_delete => true, :durable => false))
|
94
|
+
logger.debug { "reply queue: #{queue_def.denormalise}" }
|
98
95
|
|
99
96
|
@reply_queue_completion ||= EM::Completion.new.tap do |completion|
|
100
|
-
Receiver.new(
|
97
|
+
Receiver.new(queue_def) do |queue|
|
101
98
|
queue.subscribe do |payload, receiver|
|
102
99
|
@reply_container.delete(receiver.correlation_id).tap do |reply|
|
103
100
|
if reply
|
104
101
|
reply[:timeout].cancel_timeout
|
105
102
|
reply[:reply_proc].call(payload, receiver)
|
106
103
|
else
|
107
|
-
|
104
|
+
receiver.ack if opts[:auto_ack]
|
105
|
+
logger.error { "No reply block for correlation_id: #{receiver.correlation_id}. This is probably a timed out message. Message: #{payload.to_json}" }
|
108
106
|
end
|
109
107
|
end
|
110
108
|
end
|
@@ -156,7 +154,7 @@ module Smith
|
|
156
154
|
end
|
157
155
|
|
158
156
|
def counter
|
159
|
-
@message_counts[@
|
157
|
+
@message_counts[@queue_def.denormalise]
|
160
158
|
end
|
161
159
|
|
162
160
|
# Define a channel error handler.
|
@@ -166,30 +164,33 @@ module Smith
|
|
166
164
|
end
|
167
165
|
end
|
168
166
|
|
167
|
+
def queue_name
|
168
|
+
@queue_def.denormalise
|
169
|
+
end
|
170
|
+
|
169
171
|
private
|
170
172
|
|
171
173
|
def _publish(message, opts, &blk)
|
172
|
-
logger.verbose { "Publishing to: [queue]: #{@
|
173
|
-
logger.verbose { "
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
raise IncompletePayload, "Message is incomplete: #{message.to_s}"
|
174
|
+
logger.verbose { "Publishing to: [queue]: #{@queue_def.denormalise}. [options]: #{opts}" }
|
175
|
+
logger.verbose { "ACL content: [queue]: #{@queue_def.denormalise}, [metadata type]: #{message.class}, [message]: #{message.inspect}" }
|
176
|
+
|
177
|
+
increment_counter
|
178
|
+
|
179
|
+
type = @acl_type_cache.get_by_type(message.class)
|
180
|
+
|
181
|
+
@exchange_completion.completion do |exchange|
|
182
|
+
exchange.publish(message.to_s, opts.merge(:type => type), &blk)
|
182
183
|
end
|
183
184
|
end
|
184
185
|
|
185
186
|
def increment_counter(value=1)
|
186
|
-
@message_counts[@
|
187
|
+
@message_counts[@queue_def.denormalise] += value
|
187
188
|
end
|
188
189
|
end
|
189
190
|
|
190
191
|
class Timeout
|
191
192
|
def initialize(timeout, opts={}, &blk)
|
192
|
-
@timeout_proc = blk || proc { |message_id| raise
|
193
|
+
@timeout_proc = blk || proc { |message_id| raise MessageTimeoutError, "Message not received within the timeout period#{(message_id) ? ": #{message_id}" : ""}" }
|
193
194
|
@timeout_duration = timeout
|
194
195
|
end
|
195
196
|
|
@@ -198,7 +199,7 @@ module Smith
|
|
198
199
|
cancel_timeout
|
199
200
|
if @timeout_duration
|
200
201
|
@timeout = EventMachine::Timer.new(@timeout_duration) do
|
201
|
-
@timeout_proc.call(message_id)
|
202
|
+
@timeout_proc.call(message_id, @timeout_duration)
|
202
203
|
end
|
203
204
|
else
|
204
205
|
raise ArgumentError, "on_timeout not set."
|
@@ -212,6 +213,10 @@ module Smith
|
|
212
213
|
def cancel_timeout
|
213
214
|
@timeout.cancel if @timeout
|
214
215
|
end
|
216
|
+
|
217
|
+
def to_s
|
218
|
+
"<Smith::Timeout: #{@timeout_duration}>"
|
219
|
+
end
|
215
220
|
end
|
216
221
|
end
|
217
222
|
end
|
data/lib/smith/messaging/util.rb
CHANGED
@@ -41,20 +41,10 @@ module Smith
|
|
41
41
|
end
|
42
42
|
end
|
43
43
|
|
44
|
-
def normalise(name)
|
45
|
-
"#{Smith.config.smith.namespace}.#{name}"
|
46
|
-
end
|
47
|
-
|
48
44
|
def random(prefix = '', suffix = '')
|
49
45
|
"#{prefix}#{SecureRandom.hex(8)}#{suffix}"
|
50
46
|
end
|
51
47
|
|
52
|
-
# Return the queue name and options based on whether the
|
53
|
-
# queue_definition is of type QueueDefinition.
|
54
|
-
def get_queue_name_and_options(queue_definition, opts)
|
55
|
-
(queue_definition.is_a?(QueueDefinition)) ? queue_definition.to_a : [queue_definition, opts]
|
56
|
-
end
|
57
|
-
|
58
48
|
def option_or_default(options, key, default, &blk)
|
59
49
|
if options.is_a?(Hash)
|
60
50
|
if options.key?(key)
|
@@ -2,10 +2,13 @@
|
|
2
2
|
|
3
3
|
module Smith
|
4
4
|
module QueueDefinitions
|
5
|
-
Agency_control = QueueDefinition.new("#{Smith.hostname}.agency.control", :
|
6
|
-
Agent_keepalive = QueueDefinition.new("#{Smith.hostname}.agent.keepalive", :auto_delete => false, :durable =>
|
7
|
-
Agent_lifecycle = QueueDefinition.new("#{Smith.hostname}.agent.lifecycle", :auto_delete => false, :durable =>
|
5
|
+
Agency_control = QueueDefinition.new("#{Smith.hostname}.agency.control", :auto_ack => false, :durable => true, :persistent => false, :strict => true)
|
6
|
+
Agent_keepalive = QueueDefinition.new("#{Smith.hostname}.agent.keepalive", :auto_delete => false, :durable => true)
|
7
|
+
Agent_lifecycle = QueueDefinition.new("#{Smith.hostname}.agent.lifecycle", :auto_delete => false, :durable => true)
|
8
8
|
|
9
|
-
Agent_stats = QueueDefinition.new('agent.stats', :durable =>
|
9
|
+
Agent_stats = QueueDefinition.new('agent.stats', :durable => true, :auto_delete => true)
|
10
|
+
|
11
|
+
# Something tells me that I've crossed line with this.
|
12
|
+
Agent_control = ->(uuid) { QueueDefinition.new("agent.control.#{uuid}", :durable => false, :auto_delete => true) }
|
10
13
|
end
|
11
14
|
end
|
data/lib/smith/version.rb
CHANGED
data/lib/smith.rb
CHANGED
@@ -4,11 +4,9 @@ require 'tmpdir'
|
|
4
4
|
require "socket"
|
5
5
|
require 'logging'
|
6
6
|
require 'pathname'
|
7
|
+
require 'protobuf'
|
7
8
|
require 'fileutils'
|
8
|
-
require 'optimism'
|
9
|
-
require 'dm-core'
|
10
9
|
require 'securerandom'
|
11
|
-
require 'dm-yaml-adapter'
|
12
10
|
require 'extlib/string'
|
13
11
|
require 'extlib/inflection'
|
14
12
|
require 'daemons/pidfile'
|
@@ -35,8 +33,12 @@ module Smith
|
|
35
33
|
Config.get
|
36
34
|
end
|
37
35
|
|
36
|
+
def config_path
|
37
|
+
Smith.config.path
|
38
|
+
end
|
39
|
+
|
38
40
|
def root_path
|
39
|
-
Pathname.new(
|
41
|
+
Pathname.new(__FILE__).dirname.parent.expand_path
|
40
42
|
end
|
41
43
|
|
42
44
|
def agent_paths
|
@@ -52,19 +54,14 @@ module Smith
|
|
52
54
|
path_to_pathnames(config.agency.acl_path)
|
53
55
|
end
|
54
56
|
|
55
|
-
|
56
|
-
|
57
|
+
def cache_path
|
58
|
+
Pathname.new(config.agency.cache_path).expand_path
|
59
|
+
end
|
60
|
+
|
61
|
+
# Return the acl cache path.
|
57
62
|
def acl_cache_path
|
58
|
-
@acl_cache_path
|
59
|
-
|
60
|
-
else
|
61
|
-
cache_dir = Pathname.new(ENV['HOME']).join('.smith').join('acl')
|
62
|
-
if cache_dir.exist?
|
63
|
-
cache_dir
|
64
|
-
else
|
65
|
-
FileUtils.mkdir_p(cache_dir)
|
66
|
-
cache_dir
|
67
|
-
end
|
63
|
+
@acl_cache_path = Pathname.new(Smith.config.agency.acl_cache_path).tap do |path|
|
64
|
+
check_path(path, true)
|
68
65
|
end
|
69
66
|
end
|
70
67
|
|
@@ -73,26 +70,24 @@ module Smith
|
|
73
70
|
@compiler.compile
|
74
71
|
end
|
75
72
|
|
76
|
-
# Load all acls. This fucking horrible but for the time
|
77
|
-
# being it's how it's going to be. This will really start
|
78
|
-
# to be a problem when there are a lot of acls.
|
79
|
-
def load_acls
|
80
|
-
Pathname.glob(Smith.acl_cache_path.join("*.pb.rb"))do |acl_file|
|
81
|
-
logger.verbose { "Loading acl file: #{acl_file}" }
|
82
|
-
require acl_file
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
73
|
def running?
|
87
74
|
EM.reactor_running?
|
88
75
|
end
|
89
76
|
|
90
77
|
def start(opts={}, &block)
|
91
|
-
EM.epoll
|
92
|
-
|
93
|
-
|
78
|
+
if EM.epoll? && Smith.config.eventmachine.epoll
|
79
|
+
logger.debug { "Using epoll for I/O event notification." }
|
80
|
+
EM.epoll
|
81
|
+
end
|
82
|
+
|
83
|
+
if EM.kqueue? && Smith.config.eventmachine.kqueue
|
84
|
+
logger.debug { "Using kqueue for I/O event notification." }
|
85
|
+
EM.kqueue
|
86
|
+
end
|
87
|
+
|
88
|
+
EM.set_descriptor_table_size(Smith.config.eventmachine.file_descriptors)
|
94
89
|
|
95
|
-
connection_settings = config.amqp.broker.
|
90
|
+
connection_settings = config.amqp.broker.merge(
|
96
91
|
:on_tcp_connection_failure => method(:tcp_connection_failure_handler),
|
97
92
|
:on_possible_authentication_failure => method(:authentication_failure_handler))
|
98
93
|
|
@@ -102,7 +97,7 @@ module Smith
|
|
102
97
|
connection.on_connection do
|
103
98
|
broker = connection.broker.properties
|
104
99
|
endpoint = connection.broker_endpoint
|
105
|
-
logger.
|
100
|
+
logger.info { "Connected to: AMQP Broker: #{endpoint}, (#{broker['product']}/v#{broker['version']})" } unless opts[:quiet]
|
106
101
|
end
|
107
102
|
|
108
103
|
connection.on_tcp_connection_loss do |connection, settings|
|
@@ -195,32 +190,38 @@ module Smith
|
|
195
190
|
end
|
196
191
|
end
|
197
192
|
|
198
|
-
def check_path(path)
|
199
|
-
|
193
|
+
def check_path(path, create=false)
|
194
|
+
unless path.exist?
|
195
|
+
error_message = "Path does not exist: #{path}"
|
196
|
+
if create
|
197
|
+
logger.info { "Path does not exist: #{path}. Creating" }
|
198
|
+
path.mkpath
|
199
|
+
else
|
200
|
+
logger.warn { "Path does not exist: #{path}" }
|
201
|
+
end
|
202
|
+
end
|
200
203
|
end
|
204
|
+
|
201
205
|
end
|
202
206
|
end
|
203
207
|
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
require_relative 'smith/messaging/sender'
|
225
|
-
|
226
|
-
require_relative 'smith/queue_definitions'
|
208
|
+
require 'smith/amqp_errors'
|
209
|
+
require 'smith/object_count'
|
210
|
+
require 'smith/cache'
|
211
|
+
require 'smith/exceptions'
|
212
|
+
require 'smith/object_count'
|
213
|
+
require 'smith/version'
|
214
|
+
require 'smith/acl_parser'
|
215
|
+
|
216
|
+
require 'smith/messaging/acl_type_cache'
|
217
|
+
require 'smith/messaging/queue_definition'
|
218
|
+
require 'smith/messaging/amqp_options'
|
219
|
+
require 'smith/messaging/queue_factory'
|
220
|
+
require 'smith/messaging/factory'
|
221
|
+
require 'smith/messaging/acl/default'
|
222
|
+
require 'smith/messaging/util'
|
223
|
+
require 'smith/messaging/responder'
|
224
|
+
require 'smith/messaging/receiver'
|
225
|
+
require 'smith/messaging/sender'
|
226
|
+
|
227
|
+
require 'smith/queue_definitions'
|