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
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}" }
|