smith 0.6.5.2 → 0.6.7

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 28e4e29c427b83d0923d75bdf2789e01dfec90ff
4
- data.tar.gz: ec4ecc625c7c52fc8079d9eb9e97bb5c56af40fb
3
+ metadata.gz: ac264c23960916b555109d48e592a8560447182f
4
+ data.tar.gz: 424cd6d244fbdce54cffce746aeb4f81635515e8
5
5
  SHA512:
6
- metadata.gz: a8d70474e776f60812b052223c253790e4e29ef69b48dfda51dc52513bffa3798b2135db4759131ea9174fa10ec70895f9ffbc4b0aa5852ff2c26c0d869183d9
7
- data.tar.gz: 4658f5f3d511ad13374cf4fc99cddd46a10aaa483f846acfacf5c61aeae5c170ef95002015d85a36d954b0cada657b84c4ab9145bc9d39566c52b81a1eeff592
6
+ metadata.gz: 9e73b594b540c6d136a5e9ed783531aa378603b28a0f1caa408e40a0f412d7583437b42b21fbcb14ec7566a6f339183a20f5dc51b7e823ea8970dd5ff8b98ff9
7
+ data.tar.gz: 894a371746a71b6af111614db36c5a6f9f58e6f070f2bbb2b1e16f6eba97904d16f1fd334e56ea335bd4058de372adff0b7123c4365eb8b1dfd206a750d3cfc0
data/lib/smith/agent.rb CHANGED
@@ -89,7 +89,7 @@ module Smith
89
89
  queue = agent.instance_variable_get(:@signal_handler_queue)
90
90
  signal = queue.pop
91
91
 
92
- agent.send(:logger).debug { "Running signal handlers for agent: #{agent.name}: #{signal}" }
92
+ # agent.send(:logger).debug { "Running signal handlers for agent: #{agent.name}: #{signal}" }
93
93
  handlers[signal].each { |handler| handler.call(signal) }
94
94
  end
95
95
  })
@@ -108,7 +108,6 @@ module Smith
108
108
  @signal_handlers[signal].insert((position == :beginning) ? 0 : -1, blk)
109
109
 
110
110
  Signal.trap(signal) {
111
- logger.debug { "Got signal: #{signal}" }
112
111
  @signal_handler_pipe_writer.write_nonblock('.')
113
112
  @signal_handler_queue << signal
114
113
  }
@@ -9,6 +9,8 @@ module Smith
9
9
  class AgentProcess
10
10
 
11
11
  include Smith::Logger
12
+ include Utils
13
+
12
14
  extend Forwardable
13
15
 
14
16
  class AgentState < ::Protobuf::Message
@@ -75,7 +77,7 @@ module Smith
75
77
  end
76
78
 
77
79
  event :kill do
78
- transition [:null, :unknown, :starting, :acknowledge_start, :stopping, :acknowledge_stop, :running, :dead] => :null
80
+ transition [:null, :unknown, :checked, :starting, :acknowledge_start, :stopping, :acknowledge_stop, :running, :dead] => :null
79
81
  end
80
82
  end
81
83
 
@@ -131,9 +133,7 @@ module Smith
131
133
  end
132
134
 
133
135
  def exists?
134
- Smith.agent_paths.detect do |path|
135
- Pathname.new(path).join("#{name.snake_case}.rb").exist?
136
- end
136
+ agent_path(name)
137
137
  end
138
138
 
139
139
  def to_s
@@ -8,7 +8,6 @@ $:.unshift(Pathname.new(__FILE__).dirname.parent.expand_path)
8
8
 
9
9
  require 'smith'
10
10
  require 'smith/agent'
11
- # require 'smith/synchronous_agent'
12
11
 
13
12
  module Smith
14
13
  class AgentBootstrap
@@ -16,6 +15,7 @@ module Smith
16
15
  attr_reader :agent
17
16
 
18
17
  include Logger
18
+ include Utils
19
19
 
20
20
  def initialize(name, uuid)
21
21
  Dir.chdir('/')
@@ -27,7 +27,6 @@ module Smith
27
27
  Thread.abort_on_exception = true
28
28
  @agent_name = name
29
29
  @agent_uuid = uuid
30
- @agent_filename = agent_path(name)
31
30
  end
32
31
 
33
32
  def signal_handlers
@@ -41,20 +40,19 @@ module Smith
41
40
  end
42
41
 
43
42
  def load_agent
44
- @agent_filename = agent_path(@agent_name)
45
- logger.debug { "Loading #{@agent_name} from: #{@agent_filename.dirname}" }
46
- add_agent_load_path
47
- load @agent_filename
48
- @agent = Kernel.const_get(@agent_name).new(@agent_uuid)
49
- end
50
-
51
- def agent_path(name)
52
- file_name = "#{name.snake_case}.rb"
53
- Smith.agent_paths.each do |path|
54
- p = Pathname.new(path).join(file_name)
55
- return p if p.exist?
43
+ path = agent_path(@agent_name)
44
+ logger.debug { "Loading #{@agent_name} from: #{path.dirname}" }
45
+ add_agent_load_path(path)
46
+ load path
47
+
48
+ begin
49
+ @agent = class_from_name(@agent_name).new(@agent_uuid)
50
+ rescue NameError => e
51
+ # TODO: include the class name from the path.
52
+ logger.fatal { "Cannot instantiate agent. The class name: #{@agent_name} probably didn't match the path" }
53
+ terminate!
54
+ false
56
55
  end
57
- return nil
58
56
  end
59
57
 
60
58
  def start!
@@ -128,8 +126,8 @@ module Smith
128
126
  #
129
127
  # This needs to be better thought out.
130
128
  # TODO think this through some more.
131
- def add_agent_load_path
132
- path = @agent_filename.dirname.dirname.join('lib')
129
+ def add_agent_load_path(path)
130
+ path = path.dirname.dirname.join('lib')
133
131
  # The load path may be a pathname or a string. Change to strings.
134
132
  unless $:.detect { |p| p.to_s == path.to_s }
135
133
  logger.debug { "Adding #{path} to load path" }
@@ -158,9 +156,10 @@ bootstrapper = Smith::AgentBootstrap.new(name, uuid)
158
156
  # is an exception the reactor is not going going to be running.
159
157
  begin
160
158
  Smith.start do
161
- bootstrapper.load_agent
162
- bootstrapper.signal_handlers
163
- bootstrapper.start!
159
+ if bootstrapper.load_agent
160
+ bootstrapper.signal_handlers
161
+ bootstrapper.start!
162
+ end
164
163
  end
165
164
  bootstrapper.shutdown
166
165
  rescue Exception => e
@@ -0,0 +1,29 @@
1
+ require_relative '../common'
2
+
3
+ module Smith
4
+ module Commands
5
+ class Group < CommandBase
6
+
7
+ include Common
8
+
9
+ def execute
10
+ group do |value|
11
+ responder.succeed(value)
12
+ end
13
+ end
14
+
15
+ # Returns the agents in a group.
16
+ def group(&blk)
17
+ begin
18
+ blk.call(agent_group(target.first).join(' '))
19
+ rescue RuntimeError => e
20
+ blk.call(e.message)
21
+ end
22
+ end
23
+
24
+ def options_spec
25
+ banner "Lists the agents in a group."
26
+ end
27
+ end
28
+ end
29
+ end
@@ -30,7 +30,7 @@ module Smith
30
30
  on_work = ->(message, iter) do
31
31
 
32
32
  error_handler = -> (e) do
33
- if options[:no_fail]
33
+ if options[:ignore_errors]
34
34
  logger.error { "#{e} #{message.strip}" }
35
35
  iter.call
36
36
  else
@@ -90,14 +90,14 @@ module Smith
90
90
  def options_spec
91
91
  banner "Send a message to a queue. The ACL can also be specified."
92
92
 
93
- opt :type, "message type", :type => :string, :default => 'default', :short => :t
94
- opt :message, "the message, as json", :type => :string, :short => :m
95
- opt :file, "read messages from the named file", :type => :string, :short => :f
96
- opt :number, "the number of times to send the message", :type => :integer, :default => 1, :short => :n
97
- opt :reply, "set a reply listener.", :short => :r
98
- opt :timeout, "timeout when waiting for a reply", :type => :integer, :depends => :reply, :default => Smith.config.smith.timeout
99
- opt :dynamic, "send message to a dynamic queue", :type => :boolean, :default => false, :short => :d
100
- opt :no_fail, "continue to process input data if there is an error", :type => :boolean, :default => false
93
+ opt :type, "message type", :type => :string, :default => 'default', :short => :t
94
+ opt :message, "the message, as json", :type => :string, :short => :m
95
+ opt :file, "read messages from the named file", :type => :string, :short => :f
96
+ opt :number, "the number of times to send the message", :type => :integer, :default => 1, :short => :n
97
+ opt :reply, "set a reply listener.", :short => :r
98
+ opt :timeout, "timeout when waiting for a reply", :type => :integer, :depends => :reply, :default => Smith.config.smith.timeout
99
+ opt :dynamic, "send message to a dynamic queue", :type => :boolean, :default => false, :short => :d
100
+ opt :ignore_errors, "continue to process input data if there is an error", :type => :boolean, :default => false
101
101
 
102
102
  conflicts :reply, :number, :file
103
103
  conflicts :message, :file
@@ -7,24 +7,16 @@ module Smith
7
7
  when 0
8
8
  responder.succeed("No queue specified. Please specify a queue.")
9
9
  else
10
- @on_error = proc do |ch,channel_close|
11
- case channel_close.reply_code
12
- when 404
13
- responder.succeed("No such queue: [#{channel_close.reply_code}]: #{channel_close.reply_text}")
14
- when 406
15
- responder.succeed("Queue not empty: [#{channel_close.reply_code}]: #{channel_close.reply_text}.")
16
- else
17
- responder.succeed("Unknown error: [#{channel_close.reply_code}]: #{channel_close.reply_text}")
18
- end
19
- end
20
-
21
- target.each do |queue_name|
10
+ worker = ->(queue_name, iter) do
22
11
  delete_queue(queue_name) do |delete_ok|
23
- delete_exchange(queue_name) do |delete_ok|
24
- responder.succeed((options[:verbose]) ? delete_ok.message_count.to_s : nil)
25
- end
12
+ delete_exchange(queue_name, &iter)
26
13
  end
27
14
  end
15
+
16
+ # FIXME: Return errors to the caller rather than doing nothing or logging errors
17
+ done = -> { responder.succeed }
18
+
19
+ EM::Iterator.new(target).each(worker, done)
28
20
  end
29
21
  end
30
22
 
@@ -33,14 +25,26 @@ module Smith
33
25
  def options_spec
34
26
  banner "Display or remove a message from the named queue."
35
27
 
36
- opt :force, "force the removal even if there are messages on the queue", :short => :f
37
- opt :verbose, "print the number of messages deleted", :short => :v
28
+ opt :force, "force the removal even if there are messages on the queue", :short => :f
29
+ opt :ignore_errors, "ignore any errors.", :default => false
30
+ opt :log_errors, "print any errors messages.", :default => false
38
31
  end
39
32
 
40
- def delete_exchange(exchange_name, &blk)
41
- AMQP::Channel.new(Smith.connection) do |channel,ok|
42
- channel.on_error(&@on_error)
43
- channel.direct("smith.#{exchange_name}", :passive => true) do |exchange|
33
+ # Delete an exchange.
34
+ #
35
+ # @param name [String] name of the exchange.
36
+ # @yield calls the block when the exchange has been deleted
37
+ # @yieldparam [AMQ::Protocol::Channel::Close] the amqp close message
38
+ # FIXME: remove duplication
39
+ def delete_exchange(name, &blk)
40
+ AMQP::Channel.new(Smith.connection) do |channel, ok|
41
+
42
+ channel.on_error do |channel, channel_close|
43
+ handler = (options[:ignore_errors]) ? blk : nil
44
+ log_error(channel, channel_close, &handler)
45
+ end
46
+
47
+ channel.direct("smith.#{name}", :passive => true) do |exchange|
44
48
  exchange_options = (options[:force]) ? {} : {:if_unused => true}
45
49
  exchange.delete(exchange_options) do |delete_ok|
46
50
  blk.call(delete_ok)
@@ -49,9 +53,19 @@ module Smith
49
53
  end
50
54
  end
51
55
 
56
+ # Delete an queue.
57
+ #
58
+ # @param name [String] name of the queue.
59
+ # @yield calls the block when the queue has been deleted
60
+ # @yieldparam [AMQ::Protocol::Channel::Close] the amqp close message
61
+ # FIXME: remove duplication
52
62
  def delete_queue(queue_name, &blk)
53
- AMQP::Channel.new(Smith.connection) do |channel,ok|
54
- channel.on_error(&@on_error)
63
+ AMQP::Channel.new(Smith.connection) do |channel, ok|
64
+ channel.on_error do |channel, channel_close|
65
+ handler = (options[:ignore_errors]) ? blk : nil
66
+ log_error(channel, channel_close, &handler)
67
+ end
68
+
55
69
  channel.queue("smith.#{queue_name}", :passive => true) do |queue|
56
70
  queue_options = (options[:force]) ? {} : {:if_unused => true, :if_empty => true}
57
71
  queue.delete(queue_options) do |delete_ok|
@@ -61,6 +75,21 @@ module Smith
61
75
  end
62
76
  end
63
77
 
78
+ # Get's called when there is a channel error.
79
+ #
80
+ # @param channel [AMQP::Channel] the channel that errored
81
+ # @param channel_close [AMQ::Protocol::Channel::Close] the amqp close message
82
+ # which contains details of why the channel was claosed.
83
+ def log_error(channel, channel_close, &blk)
84
+ base_error_msg = "#{channel_close.reply_code}, #{channel_close.reply_text}."
85
+ if blk
86
+ logger.error { "#{base_error_msg}. Ignoring as requested" } if options[:log_errors]
87
+ blk.call
88
+ else
89
+ responder.succeed(base_error_msg)
90
+ end
91
+ end
92
+
64
93
  def extract_queue(message)
65
94
  match = /.*?'(.*?)'.*$/.match(message) #[1]
66
95
  if match && match[1]
@@ -1,16 +1,18 @@
1
1
  # -*- encoding: utf-8 -*-
2
- module Smith
3
2
 
3
+ module Smith
4
4
  module ACL
5
5
  class Factory
6
6
  include Logger
7
7
 
8
+ extend Utils
9
+
8
10
  class << self
9
11
  def create(type, content=nil, &blk)
10
12
  if type.respond_to?(:serialize_to_string)
11
13
  return type
12
14
  else
13
- clazz = (type.is_a?(::Protobuf::Message)) ? type : get_clazz(type)
15
+ clazz = (type.is_a?(::Protobuf::Message)) ? type : class_from_name(type)
14
16
 
15
17
  if blk
16
18
  clazz.new.tap { |m| blk.call(m) }
@@ -19,10 +21,6 @@ module Smith
19
21
  end
20
22
  end
21
23
  end
22
-
23
- def get_clazz(type)
24
- type.to_s.split(/::/).inject(Kernel) { |acc, t| acc.const_get(t) }
25
- end
26
24
  end
27
25
  end
28
26
  end
@@ -0,0 +1,42 @@
1
+ module Smith
2
+ module Utils
3
+
4
+ # Searches the agent load path for agents. If there are multiple agents
5
+ # with the same name in different directories the first wins.
6
+ #
7
+ # @param name [String] the name of the agent.
8
+ # @return [Pathname] the path of the agent.
9
+ def agent_path(name)
10
+ Smith.agent_paths.each do |path|
11
+ p = path_from_class(path, name)
12
+ return p if p.exist?
13
+ end
14
+ return nil
15
+ end
16
+
17
+ # Constructs a path from a root and a fully qualified class.
18
+ #
19
+ # @param root [Pathname] the root path.
20
+ # @param clazz [String] the fully qualified class.
21
+ # @@return [Pathname] the path
22
+ def path_from_class(root, clazz)
23
+ parts = clazz.split(/::/).map(&:snake_case)
24
+ parts[-1] = "#{parts[-1]}.rb"
25
+ Pathname.new(root).join(*parts)
26
+ end
27
+
28
+ def class_name_from_path(root, path)
29
+ relative_path = path.relative_path_from(root)
30
+ parts = relative_path.split
31
+ parts.map { |p| p.to_s.camel_case }.join('::')
32
+ end
33
+
34
+ # Performs a Kernel.const_get on each element of the class.
35
+ #
36
+ # @param name [String]
37
+ # @return [Class] the agent class
38
+ def class_from_name(name)
39
+ name.to_s.split(/::/).inject(Kernel) { |acc, t| acc.const_get(t) }
40
+ end
41
+ end
42
+ end
data/lib/smith/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Smith
2
- VERSION = "0.6.5.2"
2
+ VERSION = "0.6.7"
3
3
  end
data/lib/smith.rb CHANGED
@@ -208,6 +208,7 @@ module Smith
208
208
  end
209
209
  end
210
210
 
211
+ require 'smith/utils'
211
212
  require 'smith/amqp_errors'
212
213
  require 'smith/object_count'
213
214
  require 'smith/cache'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: smith
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.5.2
4
+ version: 0.6.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Richard Heycock
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-10-08 00:00:00.000000000 Z
11
+ date: 2014-11-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: oj
@@ -205,6 +205,7 @@ files:
205
205
  - lib/smith/command.rb
206
206
  - lib/smith/command_base.rb
207
207
  - lib/smith/commands/agency/agents.rb
208
+ - lib/smith/commands/agency/group.rb
208
209
  - lib/smith/commands/agency/kill.rb
209
210
  - lib/smith/commands/agency/list.rb
210
211
  - lib/smith/commands/agency/logger.rb
@@ -253,6 +254,7 @@ files:
253
254
  - lib/smith/messaging/util.rb
254
255
  - lib/smith/object_count.rb
255
256
  - lib/smith/queue_definitions.rb
257
+ - lib/smith/utils.rb
256
258
  - lib/smith/version.rb
257
259
  homepage: http://github.com/filterfish/smith2
258
260
  licenses:
@@ -279,3 +281,4 @@ signing_key:
279
281
  specification_version: 4
280
282
  summary: Multi-agent framework
281
283
  test_files: []
284
+ has_rdoc: false