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.
- 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
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
|
-
|
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
|
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
|
-
|
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 {
|
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
data/bin/smithctl
CHANGED
@@ -5,20 +5,22 @@
|
|
5
5
|
trap sig, proc { exit }
|
6
6
|
end
|
7
7
|
|
8
|
-
|
9
|
-
$:.unshift(
|
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 : :
|
21
|
-
@timeout = (options[:timeout_given]) ? options[:timeout] : Smith.config.
|
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
|
-
|
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
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
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.
|
92
|
+
Smith.compile_acls
|
95
93
|
|
96
94
|
control = SmithControl.new(opts)
|
97
95
|
|
data/lib/smith/acl_compiler.rb
CHANGED
@@ -1,89 +1,134 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
|
-
require '
|
3
|
-
require
|
4
|
-
|
5
|
-
|
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
|
18
|
-
|
19
|
-
|
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
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
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
|
-
|
48
|
-
@cache_path.to_s
|
49
|
-
end
|
45
|
+
private
|
50
46
|
|
51
|
-
|
52
|
-
|
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
|
-
|
59
|
-
path
|
60
|
-
|
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
|
-
|
63
|
-
|
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 =
|
84
|
+
cached_file = Smith.acl_cache_path.join(file.basename).sub_ext(".pb.rb")
|
72
85
|
if cached_file.exist?
|
73
|
-
|
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(
|
85
|
-
|
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 :
|
9
|
+
attr_reader :name, :pid, :uuid
|
10
10
|
|
11
|
-
def initialize(
|
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.
|
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
|
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
|
-
|
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: #{
|
123
|
+
logger.debug { "Setting up control queue: #{control_queue_def.denormalise}" }
|
132
124
|
|
133
|
-
Messaging::Receiver.new(
|
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::
|
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
|
-
|
171
|
-
p.queues << ACL::
|
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 |
|
184
|
-
payload = ACL::
|
185
|
-
p.
|
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
|
-
|
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 |
|
187
|
+
Messaging::Sender.new(QueueDefinitions::Agent_lifecycle) do |queue|
|
199
188
|
message = {:state => 'acknowledge_stop', :pid => $$, :name => self.class.to_s}
|
200
|
-
|
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, :
|
209
|
-
|
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
|
-
|
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
|
226
|
-
|
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
|
data/lib/smith/agent_cache.rb
CHANGED
@@ -1,40 +1,66 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
|
+
require 'tdb'
|
3
|
+
require 'securerandom'
|
4
|
+
|
2
5
|
module Smith
|
3
|
-
class AgentCache
|
6
|
+
class AgentCache
|
7
|
+
|
8
|
+
include Enumerable
|
4
9
|
|
5
10
|
attr_accessor :path
|
6
11
|
|
7
12
|
def initialize(opts={})
|
8
|
-
|
9
|
-
@
|
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
|
-
|
17
|
+
def create(name)
|
18
|
+
AgentProcess.new(@db, :name => name, :uuid => SecureRandom.uuid)
|
19
|
+
end
|
12
20
|
|
13
|
-
|
21
|
+
def alive?(uuid)
|
22
|
+
(@db.include?(uuid)) ? instantiate(@db[uuid]).alive? : false
|
14
23
|
end
|
15
24
|
|
16
|
-
def
|
17
|
-
|
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
|
-
|
25
|
-
|
46
|
+
def delete(uuid)
|
47
|
+
@db.delete(uuid)
|
48
|
+
end
|
26
49
|
|
27
|
-
|
50
|
+
def entry(uuid)
|
51
|
+
(uuid) ? instantiate(@db[uuid]) : nil
|
52
|
+
end
|
53
|
+
|
54
|
+
alias :[] :entry
|
28
55
|
|
29
|
-
|
30
|
-
|
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
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
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::
|
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}" }
|