smith 0.5.13.1 → 0.6.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +7 -0
  2. data/bin/agency +19 -7
  3. data/bin/pry-smith +11 -0
  4. data/bin/smithctl +19 -21
  5. data/lib/smith/acl_compiler.rb +101 -56
  6. data/lib/smith/acl_parser.rb +75 -0
  7. data/lib/smith/agent.rb +28 -43
  8. data/lib/smith/agent_cache.rb +43 -17
  9. data/lib/smith/agent_monitoring.rb +1 -1
  10. data/lib/smith/agent_process.rb +148 -53
  11. data/lib/smith/application/agency.rb +44 -54
  12. data/lib/smith/bootstrap.rb +31 -17
  13. data/lib/smith/cache.rb +4 -0
  14. data/lib/smith/command.rb +1 -3
  15. data/lib/smith/commands/agency/kill.rb +22 -5
  16. data/lib/smith/commands/agency/list.rb +9 -4
  17. data/lib/smith/commands/agency/logger.rb +25 -12
  18. data/lib/smith/commands/agency/object_count.rb +19 -8
  19. data/lib/smith/commands/agency/start.rb +7 -10
  20. data/lib/smith/commands/agency/stop.rb +30 -12
  21. data/lib/smith/commands/common.rb +1 -1
  22. data/lib/smith/commands/smithctl/acl.rb +6 -3
  23. data/lib/smith/commands/smithctl/dump.rb +79 -0
  24. data/lib/smith/commands/smithctl/firehose.rb +2 -1
  25. data/lib/smith/commands/smithctl/push.rb +27 -12
  26. data/lib/smith/commands/smithctl/status.rb +27 -0
  27. data/lib/smith/config.rb +140 -28
  28. data/lib/smith/daemon.rb +16 -3
  29. data/lib/smith/exceptions.rb +6 -3
  30. data/lib/smith/logger.rb +12 -24
  31. data/lib/smith/messaging/acl/agent_keepalive.proto +2 -2
  32. data/lib/smith/messaging/acl/agent_lifecycle.proto +15 -9
  33. data/lib/smith/messaging/acl/agent_stats.proto +6 -5
  34. data/lib/smith/messaging/acl/default.rb +2 -7
  35. data/lib/smith/messaging/acl_type_cache.rb +77 -0
  36. data/lib/smith/messaging/factory.rb +29 -0
  37. data/lib/smith/messaging/queue.rb +12 -10
  38. data/lib/smith/messaging/queue_definition.rb +21 -4
  39. data/lib/smith/messaging/receiver.rb +55 -62
  40. data/lib/smith/messaging/requeue.rb +1 -5
  41. data/lib/smith/messaging/sender.rb +48 -43
  42. data/lib/smith/messaging/util.rb +0 -10
  43. data/lib/smith/queue_definitions.rb +7 -4
  44. data/lib/smith/version.rb +1 -1
  45. data/lib/smith.rb +57 -56
  46. metadata +77 -128
  47. data/lib/smith/messaging/payload.rb +0 -100
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 95209344632520fac5a790a8efa4cfd91a52ddb2
4
+ data.tar.gz: 562bb8a1c8bd5371fdf3d74765f8c069b88f0fa0
5
+ SHA512:
6
+ metadata.gz: 2a8202bf141e34265c7254ba6dfef92d7798b8d6bd9ff7b0bc903060a27d11d86d38ba8f1b1be7aede80932f10eee31f1fd21cdb1d22655e1ffc212b039543c2
7
+ data.tar.gz: a5e5d205a49c1fd10ada42bf317fe17bde5cf12d375746133b909ea87892ecd7b35462f6b6c9cb8e8267872503799a8ee99ab6acaa921cac287221369d383718
data/bin/agency CHANGED
@@ -1,11 +1,13 @@
1
1
  #!/usr/bin/env ruby
2
2
  # -*- encoding: utf-8 -*-
3
3
 
4
- $:.unshift(File.dirname(__FILE__) + '/../lib')
4
+ require 'pathname'
5
+
6
+ $:.unshift(Pathname.new(__FILE__).dirname.parent.join('lib').expand_path)
5
7
 
6
- require 'pp'
7
8
  require 'smith'
8
9
  require 'smith/daemon'
10
+ require 'smith/agent_cache'
9
11
  require 'smith/acl_compiler'
10
12
  require 'smith/application/agency'
11
13
 
@@ -21,16 +23,19 @@ module Smith
21
23
  @options = opts
22
24
  options_check
23
25
 
24
- @daemon = Daemon.new(AGENCY_NAME, opts[:daemon], opts[:pid_dir])
25
- @agency = Agency.new(:paths => Smith.agent_paths)
26
+ @daemon = Daemon.new(add_vhost(AGENCY_NAME), opts[:daemon], opts[:pid_dir])
27
+ @agency = Agency.new
26
28
 
27
29
  Smith.shutdown_hook do
28
- puts "Shutting down"
30
+ logger.info { "Shutting down" }
29
31
  end
30
32
 
31
33
  # Setup signal handlers to clean up.
32
34
  %w{TERM INT QUIT}.each do |sig|
33
- trap sig, proc { @agency.stop }
35
+ trap sig, proc {
36
+ logger.info { "Shutting down" }
37
+ @agency.stop
38
+ }
34
39
  end
35
40
  end
36
41
 
@@ -38,10 +43,12 @@ module Smith
38
43
  if @daemon.running?
39
44
  logger.fatal { "The agency is alredy running" }
40
45
  else
46
+ logger.info { "Using config file: #{Smith.config_path}" }
47
+ require 'smith/messaging/acl_type_cache'
48
+
41
49
  @daemon.daemonise
42
50
 
43
51
  Smith.compile_acls
44
- Smith.load_acls
45
52
 
46
53
  Smith.start do
47
54
  # This block is here so the that the shutdown hook added in
@@ -66,6 +73,11 @@ module Smith
66
73
  puts "Logger set to stdout and daemonise is true. Log messages will be sent to /dev/null."
67
74
  end
68
75
  end
76
+
77
+ def add_vhost(name)
78
+ suffix = Pathname.new(Smith.config.amqp.broker.vhost).basename
79
+ "%s.%s" % [name, (suffix.root?) ? 'root' : suffix.to_s]
80
+ end
69
81
  end
70
82
  end
71
83
 
data/bin/pry-smith ADDED
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- encoding: utf-8 -*-
3
+
4
+ require 'pathname'
5
+ $:.unshift(Pathname.new(__FILE__).dirname.parent.join('lib').expand_path)
6
+
7
+ require 'pry'
8
+ require 'smith'
9
+
10
+ Smith.compile_acls
11
+ Pry::CLI.parse_options
data/bin/smithctl CHANGED
@@ -5,20 +5,22 @@
5
5
  trap sig, proc { exit }
6
6
  end
7
7
 
8
-
9
- $:.unshift(File.dirname(__FILE__) + '/../lib')
8
+ require 'pathname'
9
+ $:.unshift(Pathname.new(__FILE__).dirname.parent.join('lib').expand_path)
10
10
 
11
11
  require 'smith'
12
+ require 'smith/command'
13
+
14
+ require 'trollop'
12
15
 
13
16
  include Smith::Logger
14
17
 
15
18
  module Smith
16
19
  class SmithControl
17
20
 
18
-
19
21
  def initialize(options={})
20
- log_level((options[:log_level_given]) ? options[:log_level].to_sym : :info)
21
- @timeout = (options[:timeout_given]) ? options[:timeout] : Smith.config.agency.timeout
22
+ log_level((options[:log_level_given]) ? options[:log_level].to_sym : :warn)
23
+ @timeout = (options[:timeout_given]) ? options[:timeout] : Smith.config.smith.timeout
22
24
  end
23
25
 
24
26
  def send_command(command, args, &blk)
@@ -37,23 +39,19 @@ module Smith
37
39
 
38
40
  def agency_command(command, args, &blk)
39
41
  Messaging::Sender.new(QueueDefinitions::Agency_control) do |sender|
42
+ sender.on_timeout(5) { |message_id| blk.call("Timeout. Is the agency still running?") }
40
43
 
41
- timeout = Messaging::Timeout.new(5) { |message_id| blk.call("Timeout. Is the agency still running?") }
42
-
43
- sender.on_reply(:timeout => timeout) do |reply_payload, r|
44
- r.ack
44
+ sender.on_reply(:auto_ack => true) do |reply_payload, r|
45
45
  blk.call(reply_payload[:response])
46
46
  end
47
47
 
48
- # callback = proc do |sender|
49
- sender.publish(Smith::ACL::Factory.create(:agency_command, :command => command, :args => args))
50
- # end
51
-
52
- # errback = proc do
53
- # blk.call("Agency not running.")
54
- # end
55
-
56
- # sender.consumers?(callback, errback)
48
+ sender.consumer_count do |count|
49
+ if count > 0
50
+ sender.publish(Smith::ACL::AgencyCommand.new(:command => command, :args => args))
51
+ else
52
+ blk.call("Agency not running.")
53
+ end
54
+ end
57
55
  end
58
56
  end
59
57
  end
@@ -84,14 +82,14 @@ Usage:
84
82
  end
85
83
  end
86
84
 
87
- command = ARGV.shift
88
- args = ARGV
85
+ command = ARGV.shift.dup
86
+ args = ARGV.map {|a| a.dup}
89
87
 
90
88
  %w{TERM INT QUIT}.each do |sig|
91
89
  trap sig, proc { (Smith.running?) ? Smith.stop(true) : exit}
92
90
  end
93
91
 
94
- Smith.load_acls
92
+ Smith.compile_acls
95
93
 
96
94
  control = SmithControl.new(opts)
97
95
 
@@ -1,89 +1,134 @@
1
1
  # -*- encoding: utf-8 -*-
2
- require 'pp'
3
- require 'protobuf/compiler/compiler'
4
-
5
- # There doesn't seem to be a way to turn of printing. The code is generally run
6
- # like this: log_writing unless silent but there is no way of setting silent!
7
- # So monkey patch it.
8
- class Protobuf::Visitor::Base
9
- def log_writing(filename, message="writing..."); end
10
- end
2
+ require 'ffi'
3
+ require "tempfile"
4
+ require 'ruby_parser'
5
+ require 'smith/messaging/acl_type_cache'
11
6
 
12
7
  module Smith
13
8
  class ACLCompiler
14
9
 
15
10
  include Logger
11
+ extend FFI::Library
16
12
 
17
- def initialize(force=false)
18
- # TODO Add the force code.
19
- @cache_path = Smith.acl_cache_path
13
+ def self.find_so
14
+ $:.map{|p| Pathname.new(p).join("ruby_generator.so")}.detect{|so| so.exist? }
15
+ end
16
+
17
+ ffi_lib(find_so)
18
+ attach_function(:_rprotoc_extern, [:int, :pointer], :int32)
19
+
20
+ def initialize
21
+ @acl_type_cache = AclTypeCache.instance
22
+ @acl_parser = ACLParser.new
20
23
  end
21
24
 
22
- # Compile any protocol buffer files. This checks the timestamp to see if
23
- # the file needs compiling. This is done in a subprocess to stop the agency
24
- # from dying. I think it's a problem with the class being loaded twice but
25
- # I don't actually know that so this could be considered a bit brute force.
26
25
  def compile
27
- Process.fork do
28
- logger.debug { "Protocol buffer cache path: #{@cache_path}" }
29
- Smith.acl_path.each do |path|
30
- results = {}
31
- path_glob(path) do |p|
32
- if should_compile?(p)
33
- begin
34
- logger.info { "Compiling: #{p}" }
35
- Protobuf::Compiler.compile(p.basename, p.dirname, @cache_path)
36
- rescue Racc::ParseError => e
37
- logger.error { "Cannot parse: #{p}" }
38
- end
39
- end
40
- end
26
+ $LOAD_PATH << Smith.acl_cache_path
27
+
28
+ Smith.acl_path.each do |path|
29
+ $LOAD_PATH << path
30
+
31
+ acls_files = path_glob(path)
32
+ out_of_date_acls = path_glob(path).select { |p| should_compile?(p) }
33
+ if out_of_date_acls.size > 0
34
+ compile_on_path(path, acls_files, out_of_date_acls)
35
+ end
36
+
37
+ acls_files.each do |acl_file|
38
+ acl_class_path = acl_compiled_path(acl_file)
39
+ load_acl(acl_class_path)
40
+ add_to_type_cache(acl_class_path)
41
41
  end
42
42
  end
43
- Process.wait
44
- @cache_path
45
43
  end
46
44
 
47
- def cache_path
48
- @cache_path.to_s
49
- end
45
+ private
50
46
 
51
- # Clears the Protocol Buffer cache. If acl_cache_path is
52
- # specified in the config then the directory itself won't be removed
53
- # but if it's not specified and a temporary directory was created then
54
- # the directory is removed as well.
55
- def clear_cache
56
- logger.info { "Clearing the Protocol Buffer cache: #{Smith.acl_cache_path}" }
47
+ def compile_on_path(path, acls, out_of_date_acls)
48
+ out_of_date_acls.each { |acl| logger.debug("Compiling acl: #{path.join(acl)}") }
57
49
 
58
- Pathname.glob(@cache_path.join("*")).each do |path|
59
- path.unlink
60
- end
50
+ unless acls.empty?
51
+ Dir.chdir(path) do
52
+ begin
53
+ GC.disable
54
+
55
+ args = ["rprotoc", "--ruby_out", Smith.acl_cache_path, "--proto_path", path].map {|a| ::FFI::MemoryPointer.from_string(a.to_s.dup) }
56
+
57
+ ffi_acls = acls.map do |acl|
58
+ FFI::MemoryPointer.from_string(acl.to_s.dup)
59
+ end
60
+ ffi_acls << nil
61
+
62
+ args += ffi_acls
63
+ argv = FFI::MemoryPointer.new(:pointer, args.size)
64
+
65
+ args.each_with_index { |p, index| argv[index].put_pointer(0, p) }
61
66
 
62
- unless Smith.config.agency._has_key?(:acl_cache_path)
63
- @cache_path.rmdir
67
+ errors = capture_stderr do
68
+ self._rprotoc_extern(args.compact.size, argv)
69
+ end.split("\n")
70
+
71
+ errors.each do |error|
72
+ logger.fatal { "Cannot compile ACLs: #{error}" }
73
+ raise RuntimeError, error
74
+ end
75
+ ensure
76
+ GC.enable
77
+ end
78
+ end
64
79
  end
65
80
  end
66
81
 
67
- private
68
-
69
82
  # Returns true if the .proto file is newer that the .pb.rb file
70
83
  def should_compile?(file)
71
- cached_file = @cache_path.join(file.basename).sub_ext(".pb.rb")
84
+ cached_file = Smith.acl_cache_path.join(file.basename).sub_ext(".pb.rb")
72
85
  if cached_file.exist?
73
- if file.mtime > cached_file.mtime
74
- true
75
- else
76
- false
77
- end
86
+ file.mtime > cached_file.mtime
78
87
  else
79
88
  true
80
89
  end
81
90
  end
82
91
 
83
92
  def path_glob(path)
84
- Pathname.glob("#{path.join("*.proto")}").map do |acl|
85
- yield acl.realpath
93
+ Pathname.glob(path.join("*.proto")).map { |acl| acl.realpath }
94
+ end
95
+
96
+ # This is not idea but I really don't know how else to do it. I cannot use
97
+ # $stderr = StringIO.new as this only seems to capture STDERR if you
98
+ # explicitly write to STDERR. In my case it's an ffi library call that's
99
+ # writing to STDERR.
100
+ def capture_stderr
101
+ org_stderr = STDERR.dup
102
+ begin
103
+ tmp = Tempfile.new('')
104
+ tmp.sync = true
105
+ STDERR.reopen(tmp)
106
+ yield
107
+ File.read(tmp.path)
108
+ ensure
109
+ STDERR.reopen(org_stderr)
86
110
  end
87
111
  end
112
+
113
+ def load_acl(path)
114
+ logger.verbose { "Loading ACL: #{path}" }
115
+ require path
116
+ end
117
+
118
+ def add_to_type_cache(path)
119
+ acl_class = File.read(path)
120
+ @acl_parser.go(acl_class)
121
+ @acl_parser.fully_qualified_classes.each do |clazz|
122
+ @acl_type_cache.add(to_class(clazz))
123
+ end
124
+ end
125
+
126
+ def to_class(type_as_array)
127
+ type_as_array.inject(Kernel) { |acc, t| acc.const_get(t) }
128
+ end
129
+
130
+ def acl_compiled_path(path)
131
+ "#{Smith.acl_cache_path.join(path.basename('.proto'))}.pb.rb"
132
+ end
88
133
  end
89
134
  end
@@ -0,0 +1,75 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'set'
4
+ require 'sexp_processor'
5
+ require 'ruby_parser'
6
+ require 'optparse'
7
+ require 'timeout'
8
+
9
+ module Smith
10
+ class ACLParser < SexpProcessor
11
+
12
+ def initialize
13
+ super()
14
+ @class_stack = []
15
+ self.auto_shift_type = true
16
+ self.reset
17
+ end
18
+
19
+ def go(ruby)
20
+ @parser = RubyParser.new
21
+ process(@parser.process(ruby))
22
+ end
23
+
24
+ # Adds name to the class stack, for the duration of the block
25
+ def in_class(name)
26
+ @class_stack.unshift(name)
27
+ yield
28
+ @class_stack.shift
29
+ end
30
+
31
+ # Returns the first class in the list, or :main
32
+ def class_name
33
+ if @class_stack.any?
34
+ @class_stack.reverse
35
+ else
36
+ :main
37
+ end
38
+ end
39
+
40
+ # Process each element of #exp in turn.
41
+ def process_until_empty(exp)
42
+ process(exp.shift) until exp.empty?
43
+ end
44
+
45
+ def fully_qualified_classes
46
+ @classes.delete(:main)
47
+ @classes.inject([]) do |a, class_method|
48
+ a.tap do |acc|
49
+ acc << class_method
50
+ end
51
+ end
52
+ end
53
+
54
+ # Reset @classes data
55
+ def reset
56
+ @classes = Set.new
57
+ end
58
+
59
+ # Process Class method
60
+ def process_class(exp)
61
+ in_class(exp.shift) do
62
+ process_until_empty exp
63
+ @classes << class_name
64
+ end
65
+ s()
66
+ end
67
+
68
+ def process_module(exp)
69
+ in_class exp.shift do
70
+ process_until_empty exp
71
+ end
72
+ s()
73
+ end
74
+ end
75
+ end
data/lib/smith/agent.rb CHANGED
@@ -6,11 +6,12 @@ module Smith
6
6
  include Logger
7
7
  include Smith::ObjectCount
8
8
 
9
- attr_reader :factory, :name, :pid
9
+ attr_reader :name, :pid, :uuid
10
10
 
11
- def initialize(options={})
11
+ def initialize(uuid)
12
12
  @name = self.class.to_s
13
13
  @pid = $$
14
+ @uuid = uuid
14
15
 
15
16
  @factory = QueueFactory.new
16
17
 
@@ -67,16 +68,9 @@ module Smith
67
68
  @on_running = blk
68
69
  end
69
70
 
70
- # Override this method to implement your own agent. You can use task but this may
71
- # go away in the future. This method must not block.
71
+ # Override this method to implement your own agent.
72
72
  def run
73
- raise ArgumentError, "You need to call Agent.task(&block)" if @@task.nil?
74
-
75
- logger.debug { "Setting up default queue: #{default_queue_name}" }
76
-
77
- subscribe(default_queue_name, :auto_delete => false) do |r|
78
- @@task.call(r.payload)
79
- end
73
+ raise ArgumentError, "You must override this method"
80
74
  end
81
75
 
82
76
  def install_signal_handler(signal, position=:end, &blk)
@@ -107,16 +101,14 @@ module Smith
107
101
  end
108
102
 
109
103
  class << self
110
- def task(opts={}, &blk)
111
- @@task = blk
112
- end
113
-
114
104
  # Options supported:
115
105
  # :monitor, the agency will monitor the agent & if dies restart.
116
106
  # :singleton, only every have one agent. If this is set to false
117
107
  # multiple agents are allowed.
118
108
  def options(opts)
119
- Smith.config.agent._merge!(opts)
109
+ opts.each do |k, v|
110
+ Smith.config.agent.send("#{k}=", v)
111
+ end
120
112
  end
121
113
  end
122
114
 
@@ -128,9 +120,9 @@ module Smith
128
120
  end
129
121
 
130
122
  def setup_control_queue
131
- logger.debug { "Setting up control queue: #{control_queue_name}" }
123
+ logger.debug { "Setting up control queue: #{control_queue_def.denormalise}" }
132
124
 
133
- Messaging::Receiver.new(control_queue_name, :durable => false, :auto_delete => true) do |receiver|
125
+ Messaging::Receiver.new(control_queue_def) do |receiver|
134
126
  receiver.subscribe do |payload|
135
127
  logger.debug { "Command received on agent control queue: #{payload.command} #{payload.options}" }
136
128
 
@@ -142,7 +134,7 @@ module Smith
142
134
  when 'log_level'
143
135
  begin
144
136
  level = payload.options.first
145
- logger.info { "Setting log level to #{level} for: #{name}" }
137
+ logger.info { "Setting log level to #{level} for: #{name} (#{uuid})" }
146
138
  log_level(level)
147
139
  rescue ArgumentError => e
148
140
  logger.error { "Incorrect log level: #{level}" }
@@ -155,20 +147,18 @@ module Smith
155
147
  end
156
148
 
157
149
  def setup_stats_queue
158
- puts "setting stats"
159
- # instantiate this queue without using the factory so it doesn't show
160
- # up in the stats.
161
150
  Messaging::Sender.new(QueueDefinitions::Agent_stats) do |stats_queue|
162
151
  EventMachine.add_periodic_timer(2) do
163
152
  stats_queue.number_of_consumers do |consumers|
164
153
  if consumers > 0
165
- payload = ACL::Factory.create(:agent_stats) do |p|
154
+ payload = ACL::AgentStats.new.tap do |p|
155
+ p.uuid = uuid
166
156
  p.agent_name = self.name
167
157
  p.pid = self.pid
168
158
  p.rss = (File.read("/proc/#{pid}/statm").split[1].to_i * 4) / 1024 # This assumes the page size is 4K & is MB
169
159
  p.up_time = (Time.now - @start_time).to_i
170
- factory.each_queue do |q|
171
- p.queues << ACL::Factory.create('agent_stats::queue_stats', :name => q.denormalised_queue_name, :type => q.class.to_s, :length => q.counter)
160
+ queues.each_queue do |q|
161
+ p.queues << ACL::AgentStats::QueueStats.new(:name => q.name, :type => q.class.to_s, :length => q.counter)
172
162
  end
173
163
  end
174
164
 
@@ -180,24 +170,23 @@ module Smith
180
170
  end
181
171
 
182
172
  def acknowledge_start(&blk)
183
- Messaging::Sender.new(QueueDefinitions::Agent_lifecycle) do |ack_start_queue|
184
- payload = ACL::Factory.create(:agent_lifecycle) do |p|
185
- p.state = 'acknowledge_start'
173
+ Messaging::Sender.new(QueueDefinitions::Agent_lifecycle) do |queue|
174
+ payload = ACL::AgentAcknowledgeStart.new.tap do |p|
175
+ p.uuid = uuid
186
176
  p.pid = $$
187
- p.name = self.class.to_s
188
- p.metadata = Smith.config.agent.metadata
189
- p.monitor = Smith.config.agent.monitor
190
177
  p.singleton = Smith.config.agent.singleton
191
178
  p.started_at = Time.now.to_i
179
+ p.metadata = Smith.config.agent.metadata
180
+ p.monitor = Smith.config.agent.monitor
192
181
  end
193
- ack_start_queue.publish(payload, &blk)
182
+ queue.publish(payload)
194
183
  end
195
184
  end
196
185
 
197
186
  def acknowledge_stop(&blk)
198
- Messaging::Sender.new(QueueDefinitions::Agent_lifecycle) do |ack_stop_queue|
187
+ Messaging::Sender.new(QueueDefinitions::Agent_lifecycle) do |queue|
199
188
  message = {:state => 'acknowledge_stop', :pid => $$, :name => self.class.to_s}
200
- ack_stop_queue.publish(ACL::Factory.create(:agent_lifecycle, message), &blk)
189
+ queue.publish(ACL::AgentAcknowledgeStop.new(:uuid => uuid), &blk)
201
190
  end
202
191
  end
203
192
 
@@ -205,10 +194,10 @@ module Smith
205
194
  if Smith.config.agent.monitor
206
195
  EventMachine::add_periodic_timer(1) do
207
196
  Messaging::Sender.new(QueueDefinitions::Agent_keepalive) do |queue|
208
- message = {:name => self.class.to_s, :pid => $$, :time => Time.now.to_i}
209
- keep_alive_queue.consumers do |consumers|
197
+ message = {:name => self.class.to_s, :uuid => uuid, :time => Time.now.to_i}
198
+ queue.consumers do |consumers|
210
199
  if consumers > 0
211
- keep_alive_queue.publish(ACL::Factory.create(:agent_keepalive, message))
200
+ queue.publish(ACL::AgentKeepalive, message)
212
201
  end
213
202
  end
214
203
  end
@@ -222,12 +211,8 @@ module Smith
222
211
  @factory
223
212
  end
224
213
 
225
- def control_queue_name
226
- "#{default_queue_name}.control"
227
- end
228
-
229
- def default_queue_name
230
- "agent.#{name.sub(/Agent$/, '').snake_case}"
214
+ def control_queue_def
215
+ @control_queue_def ||= QueueDefinitions::Agent_control.call(uuid)
231
216
  end
232
217
  end
233
218
  end
@@ -1,40 +1,66 @@
1
1
  # -*- encoding: utf-8 -*-
2
+ require 'tdb'
3
+ require 'securerandom'
4
+
2
5
  module Smith
3
- class AgentCache < Cache
6
+ class AgentCache
7
+
8
+ include Enumerable
4
9
 
5
10
  attr_accessor :path
6
11
 
7
12
  def initialize(opts={})
8
- super()
9
- @paths = opts[:paths]
13
+ # @db = LevelDB::DB.make(Smith.cache_path.join('agent_state').to_s, :error_if_exists => false, :create_if_missing => true)
14
+ @db = TDB.new(Smith.cache_path.join('agent_state.tdb').to_s)
15
+ end
10
16
 
11
- operator ->(agent_name, options={}) { AgentProcess.first(:name => agent_name) || AgentProcess.new(:name => agent_name, :path => agent_path(agent_name)) }
17
+ def create(name)
18
+ AgentProcess.new(@db, :name => name, :uuid => SecureRandom.uuid)
19
+ end
12
20
 
13
- populate
21
+ def alive?(uuid)
22
+ (@db.include?(uuid)) ? instantiate(@db[uuid]).alive? : false
14
23
  end
15
24
 
16
- def alive?(name)
17
- (exist?(name)) ? entry(name).alive? : false
25
+ def exist?(uuid)
26
+ @db.include?(uuid)
18
27
  end
19
28
 
29
+ def find_by_name(*names)
30
+ inject([]) do |a, agent|
31
+ a.tap do |acc|
32
+ names.flatten.each do |name|
33
+ acc << agent if name == agent.name
34
+ end
35
+ end
36
+ end
37
+ end
38
+
39
+ # select {|a| a.name == name.to_s }
40
+ # end
41
+
20
42
  def state(state)
21
43
  select {|a| a.state == state.to_s }
22
44
  end
23
45
 
24
- alias names :entries
25
- alias :[] :entry
46
+ def delete(uuid)
47
+ @db.delete(uuid)
48
+ end
26
49
 
27
- private
50
+ def entry(uuid)
51
+ (uuid) ? instantiate(@db[uuid]) : nil
52
+ end
53
+
54
+ alias :[] :entry
28
55
 
29
- # When we start load any new data from the db.
30
- def populate
31
- AgentProcess.all.each { |a| update(a.name, a) }
56
+ def each(&blk)
57
+ @db.each {|k,v| blk.call(instantiate(v)) }
32
58
  end
33
59
 
34
- def agent_path(agent_name)
35
- @paths.detect do |path|
36
- Pathname.new(path).join("#{agent_name.snake_case}.rb").exist?
37
- end
60
+ private
61
+
62
+ def instantiate(state)
63
+ (state) ? AgentProcess.new(@db, state) : nil
38
64
  end
39
65
  end
40
66
  end
@@ -38,7 +38,7 @@ module Smith
38
38
  logger.info { "Restarting dead agent: #{agent_process.name}" }
39
39
  Messaging::Sender.new(QueueDefinitions::Agency_control) do |sender|
40
40
  sender.on_reply { |p, r| logger.debug { "Agent restart message acknowledged: #{agent_process.name}" } }
41
- sender.publish(ACL::Factory.create(:agency_command).content(:command => 'start', :args => [agent_process.name]))
41
+ sender.publish(ACL::AgencyCommand.new(:command => 'start', :args => [agent_process.name]))
42
42
  end
43
43
  when 'unknown'
44
44
  logger.info { "Agent is in an unknown state: #{agent_process.name}" }