ezmobius-nanite 0.4.0 → 0.4.1.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.
- data/README.rdoc +70 -20
- data/Rakefile +1 -1
- data/bin/nanite-agent +34 -8
- data/bin/nanite-mapper +18 -8
- data/lib/nanite.rb +71 -0
- data/lib/nanite/actor.rb +60 -0
- data/lib/nanite/actor_registry.rb +24 -0
- data/lib/nanite/admin.rb +138 -0
- data/lib/nanite/agent.rb +250 -0
- data/lib/nanite/amqp.rb +47 -0
- data/lib/nanite/cluster.rb +203 -0
- data/lib/nanite/config.rb +102 -0
- data/lib/nanite/console.rb +39 -0
- data/lib/nanite/daemonize.rb +13 -0
- data/lib/nanite/dispatcher.rb +90 -0
- data/lib/nanite/identity.rb +16 -0
- data/lib/nanite/job.rb +104 -0
- data/lib/nanite/local_state.rb +34 -0
- data/lib/nanite/log.rb +64 -0
- data/lib/nanite/log/formatter.rb +39 -0
- data/lib/nanite/mapper.rb +277 -0
- data/lib/nanite/mapper_proxy.rb +56 -0
- data/lib/nanite/packets.rb +231 -0
- data/lib/nanite/pid_file.rb +52 -0
- data/lib/nanite/reaper.rb +38 -0
- data/lib/nanite/security/cached_certificate_store_proxy.rb +24 -0
- data/lib/nanite/security/certificate.rb +55 -0
- data/lib/nanite/security/certificate_cache.rb +66 -0
- data/lib/nanite/security/distinguished_name.rb +34 -0
- data/lib/nanite/security/encrypted_document.rb +46 -0
- data/lib/nanite/security/rsa_key_pair.rb +53 -0
- data/lib/nanite/security/secure_serializer.rb +67 -0
- data/lib/nanite/security/signature.rb +40 -0
- data/lib/nanite/security/static_certificate_store.rb +35 -0
- data/lib/nanite/security_provider.rb +47 -0
- data/lib/nanite/serializer.rb +52 -0
- data/lib/nanite/state.rb +164 -0
- data/lib/nanite/streaming.rb +125 -0
- data/lib/nanite/util.rb +51 -0
- data/spec/actor_registry_spec.rb +62 -0
- data/spec/actor_spec.rb +59 -0
- data/spec/agent_spec.rb +235 -0
- data/spec/cached_certificate_store_proxy_spec.rb +34 -0
- data/spec/certificate_cache_spec.rb +49 -0
- data/spec/certificate_spec.rb +27 -0
- data/spec/cluster_spec.rb +300 -0
- data/spec/dispatcher_spec.rb +136 -0
- data/spec/distinguished_name_spec.rb +24 -0
- data/spec/encrypted_document_spec.rb +21 -0
- data/spec/job_spec.rb +219 -0
- data/spec/local_state_spec.rb +112 -0
- data/spec/packet_spec.rb +218 -0
- data/spec/rsa_key_pair_spec.rb +33 -0
- data/spec/secure_serializer_spec.rb +41 -0
- data/spec/serializer_spec.rb +107 -0
- data/spec/signature_spec.rb +30 -0
- data/spec/spec_helper.rb +23 -0
- data/spec/static_certificate_store_spec.rb +30 -0
- data/spec/util_spec.rb +63 -0
- metadata +63 -2
data/lib/nanite/agent.rb
ADDED
@@ -0,0 +1,250 @@
|
|
1
|
+
module Nanite
|
2
|
+
class Agent
|
3
|
+
include AMQPHelper
|
4
|
+
include FileStreaming
|
5
|
+
include ConsoleHelper
|
6
|
+
include DaemonizeHelper
|
7
|
+
|
8
|
+
attr_reader :identity, :options, :serializer, :dispatcher, :registry, :amq, :tags
|
9
|
+
attr_accessor :status_proc
|
10
|
+
|
11
|
+
DEFAULT_OPTIONS = COMMON_DEFAULT_OPTIONS.merge({:user => 'nanite', :ping_time => 15,
|
12
|
+
:default_services => []}) unless defined?(DEFAULT_OPTIONS)
|
13
|
+
|
14
|
+
# Initializes a new agent and establishes AMQP connection.
|
15
|
+
# This must be used inside EM.run block or if EventMachine reactor
|
16
|
+
# is already started, for instance, by a Thin server that your Merb/Rails
|
17
|
+
# application runs on.
|
18
|
+
#
|
19
|
+
# Agent options:
|
20
|
+
#
|
21
|
+
# identity : identity of this agent, may be any string
|
22
|
+
#
|
23
|
+
# status_proc : a callable object that returns agent load as a string,
|
24
|
+
# defaults to load averages string extracted from `uptime`
|
25
|
+
# format : format to use for packets serialization. One of the three:
|
26
|
+
# :marshall, :json, or :yaml. Defaults to
|
27
|
+
# Ruby's Marshall format. For interoperability with
|
28
|
+
# AMQP clients implemented in other languages, use JSON.
|
29
|
+
#
|
30
|
+
# Note that Nanite uses JSON gem,
|
31
|
+
# and ActiveSupport's JSON encoder may cause clashes
|
32
|
+
# if ActiveSupport is loaded after JSON gem.
|
33
|
+
#
|
34
|
+
# root : application root for this agent, defaults to Dir.pwd
|
35
|
+
#
|
36
|
+
# log_dir : path to directory where agent stores it's log file
|
37
|
+
# if not given, app_root is used.
|
38
|
+
#
|
39
|
+
# file_root : path to directory to files this agent provides
|
40
|
+
# defaults to app_root/files
|
41
|
+
#
|
42
|
+
# ping_time : time interval in seconds between two subsequent heartbeat messages
|
43
|
+
# this agent broadcasts. Default value is 15.
|
44
|
+
#
|
45
|
+
# console : true tells Nanite to start interactive console
|
46
|
+
#
|
47
|
+
# daemonize : true tells Nanite to daemonize
|
48
|
+
#
|
49
|
+
# pid_dir : path to the directory where the agent stores its pid file (only if daemonized)
|
50
|
+
# defaults to the root or the current working directory.
|
51
|
+
#
|
52
|
+
# services : list of services provided by this agent, by default
|
53
|
+
# all methods exposed by actors are listed
|
54
|
+
#
|
55
|
+
# single_threaded: Run all operations in one thread
|
56
|
+
#
|
57
|
+
# Connection options:
|
58
|
+
#
|
59
|
+
# vhost : AMQP broker vhost that should be used
|
60
|
+
#
|
61
|
+
# user : AMQP broker user
|
62
|
+
#
|
63
|
+
# pass : AMQP broker password
|
64
|
+
#
|
65
|
+
# host : host AMQP broker (or node of interest) runs on,
|
66
|
+
# defaults to 0.0.0.0
|
67
|
+
#
|
68
|
+
# port : port AMQP broker (or node of interest) runs on,
|
69
|
+
# this defaults to 5672, port used by some widely
|
70
|
+
# used AMQP brokers (RabbitMQ and ZeroMQ)
|
71
|
+
#
|
72
|
+
# On start Nanite reads config.yml, so it is common to specify
|
73
|
+
# options in the YAML file. However, when both Ruby code options
|
74
|
+
# and YAML file specify option, Ruby code options take precedence.
|
75
|
+
def self.start(options = {})
|
76
|
+
agent = new(options)
|
77
|
+
agent.run
|
78
|
+
agent
|
79
|
+
end
|
80
|
+
|
81
|
+
def initialize(opts)
|
82
|
+
set_configuration(opts)
|
83
|
+
@tags = []
|
84
|
+
@tags << opts[:tag]
|
85
|
+
@tags.flatten!
|
86
|
+
@options.freeze
|
87
|
+
end
|
88
|
+
|
89
|
+
def run
|
90
|
+
log_path = false
|
91
|
+
if @options[:daemonize]
|
92
|
+
log_path = (@options[:log_dir] || @options[:root] || Dir.pwd)
|
93
|
+
end
|
94
|
+
Log.init(@identity, log_path)
|
95
|
+
Log.level = @options[:log_level] if @options[:log_level]
|
96
|
+
@serializer = Serializer.new(@options[:format])
|
97
|
+
@status_proc = lambda { parse_uptime(`uptime`) rescue 'no status' }
|
98
|
+
pid_file = PidFile.new(@identity, @options)
|
99
|
+
pid_file.check
|
100
|
+
if @options[:daemonize]
|
101
|
+
daemonize
|
102
|
+
pid_file.write
|
103
|
+
at_exit { pid_file.remove }
|
104
|
+
end
|
105
|
+
@amq = start_amqp(@options)
|
106
|
+
@registry = ActorRegistry.new
|
107
|
+
@dispatcher = Dispatcher.new(@amq, @registry, @serializer, @identity, @options)
|
108
|
+
setup_mapper_proxy
|
109
|
+
load_actors
|
110
|
+
setup_traps
|
111
|
+
setup_queue
|
112
|
+
advertise_services
|
113
|
+
setup_heartbeat
|
114
|
+
at_exit { un_register } unless $TESTING
|
115
|
+
start_console if @options[:console] && !@options[:daemonize]
|
116
|
+
end
|
117
|
+
|
118
|
+
def register(actor, prefix = nil)
|
119
|
+
registry.register(actor, prefix)
|
120
|
+
end
|
121
|
+
|
122
|
+
# Can be used in agent's initialization file to register a security module
|
123
|
+
# This security module 'authorize' method will be called back whenever the
|
124
|
+
# agent receives a request and will be given the corresponding deliverable.
|
125
|
+
# It should return 'true' for the request to proceed.
|
126
|
+
# Requests will return 'deny_token' or the string "Denied" by default when
|
127
|
+
# 'authorize' does not return 'true'.
|
128
|
+
def register_security(security, deny_token = "Denied")
|
129
|
+
@security = security
|
130
|
+
@deny_token = deny_token
|
131
|
+
end
|
132
|
+
|
133
|
+
protected
|
134
|
+
|
135
|
+
def set_configuration(opts)
|
136
|
+
@options = DEFAULT_OPTIONS.clone
|
137
|
+
root = opts[:root] || @options[:root]
|
138
|
+
custom_config = if root
|
139
|
+
file = File.expand_path(File.join(root, 'config.yml'))
|
140
|
+
File.exists?(file) ? (YAML.load(IO.read(file)) || {}) : {}
|
141
|
+
else
|
142
|
+
{}
|
143
|
+
end
|
144
|
+
opts.delete(:identity) unless opts[:identity]
|
145
|
+
@options.update(custom_config.merge(opts))
|
146
|
+
@options[:file_root] ||= File.join(@options[:root], 'files')
|
147
|
+
return @identity = "nanite-#{@options[:identity]}" if @options[:identity]
|
148
|
+
token = Identity.generate
|
149
|
+
@identity = "nanite-#{token}"
|
150
|
+
File.open(File.expand_path(File.join(@options[:root], 'config.yml')), 'w') do |fd|
|
151
|
+
fd.write(YAML.dump(custom_config.merge(:identity => token)))
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
def load_actors
|
156
|
+
return unless options[:root]
|
157
|
+
actors_dir = @options[:actors_dir] || "#{@options[:root]}/actors"
|
158
|
+
actors = @options[:actors]
|
159
|
+
Dir["#{actors_dir}/*.rb"].each do |actor|
|
160
|
+
next if actors && !actors.include?(File.basename(actor, ".rb"))
|
161
|
+
Nanite::Log.info("loading actor: #{actor}")
|
162
|
+
require actor
|
163
|
+
end
|
164
|
+
init_path = @options[:initrb] || File.join(options[:root], 'init.rb')
|
165
|
+
instance_eval(File.read(init_path), init_path) if File.exist?(init_path)
|
166
|
+
end
|
167
|
+
|
168
|
+
def receive(packet)
|
169
|
+
case packet
|
170
|
+
when Advertise
|
171
|
+
Nanite::Log.debug("handling Advertise: #{packet.inspect}")
|
172
|
+
advertise_services
|
173
|
+
when Request, Push
|
174
|
+
Nanite::Log.debug("handling Request: #{packet.inspect}")
|
175
|
+
if @security && !@security.authorize(packet)
|
176
|
+
if packet.kind_of?(Request)
|
177
|
+
r = Result.new(packet.token, packet.reply_to, @deny_token, identity)
|
178
|
+
amq.queue(packet.reply_to, :no_declare => options[:secure]).publish(serializer.dump(r))
|
179
|
+
end
|
180
|
+
else
|
181
|
+
dispatcher.dispatch(packet)
|
182
|
+
end
|
183
|
+
when Result
|
184
|
+
Nanite::Log.debug("handling Result: #{packet.inspect}")
|
185
|
+
@mapper_proxy.handle_result(packet)
|
186
|
+
when IntermediateMessage
|
187
|
+
Nanite::Log.debug("handling Intermediate Result: #{packet.inspect}")
|
188
|
+
@mapper_proxy.handle_intermediate_result(packet)
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
def tag(*tags)
|
193
|
+
tags.each {|t| @tags << t}
|
194
|
+
@tags.uniq!
|
195
|
+
end
|
196
|
+
|
197
|
+
def setup_queue
|
198
|
+
amq.queue(identity, :durable => true).subscribe(:ack => true) do |info, msg|
|
199
|
+
begin
|
200
|
+
info.ack
|
201
|
+
packet = serializer.load(msg)
|
202
|
+
receive(packet)
|
203
|
+
rescue Exception => e
|
204
|
+
Nanite::Log.error("Error handling packet: #{e.message}")
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
def setup_heartbeat
|
210
|
+
EM.add_periodic_timer(options[:ping_time]) do
|
211
|
+
amq.fanout('heartbeat', :no_declare => options[:secure]).publish(serializer.dump(Ping.new(identity, status_proc.call)))
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
def setup_mapper_proxy
|
216
|
+
@mapper_proxy = MapperProxy.new(identity, options)
|
217
|
+
end
|
218
|
+
|
219
|
+
def setup_traps
|
220
|
+
['INT', 'TERM'].each do |sig|
|
221
|
+
old = trap(sig) do
|
222
|
+
un_register
|
223
|
+
amq.instance_variable_get('@connection').close do
|
224
|
+
EM.stop
|
225
|
+
old.call if old.is_a? Proc
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
def un_register
|
232
|
+
unless @unregistered
|
233
|
+
@unregistered = true
|
234
|
+
amq.fanout('registration', :no_declare => options[:secure]).publish(serializer.dump(UnRegister.new(identity)))
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
def advertise_services
|
239
|
+
Nanite::Log.debug("advertise_services: #{registry.services.inspect}")
|
240
|
+
amq.fanout('registration', :no_declare => options[:secure]).publish(serializer.dump(Register.new(identity, registry.services, status_proc.call, self.tags)))
|
241
|
+
end
|
242
|
+
|
243
|
+
def parse_uptime(up)
|
244
|
+
if up =~ /load averages?: (.*)/
|
245
|
+
a,b,c = $1.split(/\s+|,\s+/)
|
246
|
+
(a.to_f + b.to_f + c.to_f) / 3
|
247
|
+
end
|
248
|
+
end
|
249
|
+
end
|
250
|
+
end
|
data/lib/nanite/amqp.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
class MQ
|
2
|
+
class Queue
|
3
|
+
# Asks the broker to redeliver all unacknowledged messages on a
|
4
|
+
# specifieid channel. Zero or more messages may be redelivered.
|
5
|
+
#
|
6
|
+
# * requeue (default false)
|
7
|
+
# If this parameter is false, the message will be redelivered to the original recipient.
|
8
|
+
# If this flag is true, the server will attempt to requeue the message, potentially then
|
9
|
+
# delivering it to an alternative subscriber.
|
10
|
+
#
|
11
|
+
def recover requeue = false
|
12
|
+
@mq.callback{
|
13
|
+
@mq.send Protocol::Basic::Recover.new({ :requeue => requeue })
|
14
|
+
}
|
15
|
+
self
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# monkey patch to the amqp gem that adds :no_declare => true option for new
|
21
|
+
# Exchange objects. This allows us to send messeages to exchanges that are
|
22
|
+
# declared by the mappers and that we have no configuration priviledges on.
|
23
|
+
# temporary until we get this into amqp proper
|
24
|
+
MQ::Exchange.class_eval do
|
25
|
+
def initialize mq, type, name, opts = {}
|
26
|
+
@mq = mq
|
27
|
+
@type, @name, @opts = type, name, opts
|
28
|
+
@mq.exchanges[@name = name] ||= self
|
29
|
+
@key = opts[:key]
|
30
|
+
|
31
|
+
@mq.callback{
|
32
|
+
@mq.send AMQP::Protocol::Exchange::Declare.new({ :exchange => name,
|
33
|
+
:type => type,
|
34
|
+
:nowait => true }.merge(opts))
|
35
|
+
} unless name == "amq.#{type}" or name == '' or opts[:no_declare]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
module Nanite
|
40
|
+
module AMQPHelper
|
41
|
+
def start_amqp(options)
|
42
|
+
connection = AMQP.connect(:user => options[:user], :pass => options[:pass], :vhost => options[:vhost],
|
43
|
+
:host => options[:host], :port => (options[:port] || ::AMQP::PORT).to_i, :insist => options[:insist] || false)
|
44
|
+
MQ.new(connection)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,203 @@
|
|
1
|
+
module Nanite
|
2
|
+
class Cluster
|
3
|
+
attr_reader :agent_timeout, :nanites, :reaper, :serializer, :identity, :amq, :redis, :mapper
|
4
|
+
|
5
|
+
def initialize(amq, agent_timeout, identity, serializer, mapper, redis=nil)
|
6
|
+
@amq = amq
|
7
|
+
@agent_timeout = agent_timeout
|
8
|
+
@identity = identity
|
9
|
+
@serializer = serializer
|
10
|
+
@mapper = mapper
|
11
|
+
@redis = redis
|
12
|
+
@security = SecurityProvider.get
|
13
|
+
if redis
|
14
|
+
Nanite::Log.info("using redis for state storage")
|
15
|
+
require 'nanite/state'
|
16
|
+
@nanites = ::Nanite::State.new(redis)
|
17
|
+
else
|
18
|
+
require 'nanite/local_state'
|
19
|
+
@nanites = Nanite::LocalState.new
|
20
|
+
end
|
21
|
+
@reaper = Reaper.new(agent_timeout)
|
22
|
+
setup_queues
|
23
|
+
end
|
24
|
+
|
25
|
+
# determine which nanites should receive the given request
|
26
|
+
def targets_for(request)
|
27
|
+
return [request.target] if request.target
|
28
|
+
__send__(request.selector, request.type, request.tags).collect {|name, state| name }
|
29
|
+
end
|
30
|
+
|
31
|
+
# adds nanite to nanites map: key is nanite's identity
|
32
|
+
# and value is a services/status pair implemented
|
33
|
+
# as a hash
|
34
|
+
def register(reg)
|
35
|
+
case reg
|
36
|
+
when Register
|
37
|
+
if @security.authorize_registration(reg)
|
38
|
+
nanites[reg.identity] = { :services => reg.services, :status => reg.status, :tags => reg.tags }
|
39
|
+
reaper.timeout(reg.identity, agent_timeout + 1) { nanites.delete(reg.identity) }
|
40
|
+
Nanite::Log.info("registered: #{reg.identity}, #{nanites[reg.identity].inspect}")
|
41
|
+
else
|
42
|
+
Nanite::Log.warning("registration of #{reg.inspect} not authorized")
|
43
|
+
end
|
44
|
+
when UnRegister
|
45
|
+
nanites.delete(reg.identity)
|
46
|
+
Nanite::Log.info("un-registering: #{reg.identity}")
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def route(request, targets)
|
51
|
+
EM.next_tick { targets.map { |target| publish(request, target) } }
|
52
|
+
end
|
53
|
+
|
54
|
+
def publish(request, target)
|
55
|
+
# We need to initialize the 'target' field of the request object so that the serializer has
|
56
|
+
# access to it.
|
57
|
+
begin
|
58
|
+
old_target = request.target
|
59
|
+
request.target = target unless target == 'mapper-offline'
|
60
|
+
amq.queue(target).publish(serializer.dump(request), :persistent => request.persistent)
|
61
|
+
ensure
|
62
|
+
request.target = old_target
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
protected
|
67
|
+
|
68
|
+
# updates nanite information (last ping timestamps, status)
|
69
|
+
# when heartbeat message is received
|
70
|
+
def handle_ping(ping)
|
71
|
+
if nanite = nanites[ping.identity]
|
72
|
+
nanite[:status] = ping.status
|
73
|
+
reaper.reset_with_autoregister_hack(ping.identity, agent_timeout + 1) { nanites.delete(ping.identity) }
|
74
|
+
else
|
75
|
+
amq.queue(ping.identity).publish(serializer.dump(Advertise.new))
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
# forward request coming from agent
|
80
|
+
def handle_request(request)
|
81
|
+
if @security.authorize_request(request)
|
82
|
+
result = Result.new(request.token, request.from, nil, mapper.identity)
|
83
|
+
intm_handler = lambda do |res|
|
84
|
+
result.results = res
|
85
|
+
forward_response(result, request.persistent)
|
86
|
+
end
|
87
|
+
ok = mapper.send_request(request, :intermediate_handler => intm_handler) do |res|
|
88
|
+
result.results = res
|
89
|
+
forward_response(result, request.persistent)
|
90
|
+
end
|
91
|
+
if ok == false
|
92
|
+
forward_response(result, request.persistent)
|
93
|
+
end
|
94
|
+
else
|
95
|
+
Nanite::Log.warning("request #{request.inspect} not authorized")
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
# forward response back to agent that originally made the request
|
100
|
+
def forward_response(res, persistent)
|
101
|
+
amq.queue(res.to).publish(serializer.dump(res), :persistent => persistent)
|
102
|
+
end
|
103
|
+
|
104
|
+
# returns least loaded nanite that provides given service
|
105
|
+
def least_loaded(service, tags=[])
|
106
|
+
candidates = nanites_providing(service,tags)
|
107
|
+
return [] if candidates.empty?
|
108
|
+
|
109
|
+
[candidates.min { |a,b| a[1][:status] <=> b[1][:status] }]
|
110
|
+
end
|
111
|
+
|
112
|
+
# returns all nanites that provide given service
|
113
|
+
def all(service, tags=[])
|
114
|
+
nanites_providing(service,tags)
|
115
|
+
end
|
116
|
+
|
117
|
+
# returns a random nanite
|
118
|
+
def random(service, tags=[])
|
119
|
+
candidates = nanites_providing(service,tags)
|
120
|
+
return [] if candidates.empty?
|
121
|
+
|
122
|
+
[candidates[rand(candidates.size)]]
|
123
|
+
end
|
124
|
+
|
125
|
+
# selects next nanite that provides given service
|
126
|
+
# using round robin rotation
|
127
|
+
def rr(service, tags=[])
|
128
|
+
@last ||= {}
|
129
|
+
@last[service] ||= 0
|
130
|
+
candidates = nanites_providing(service,tags)
|
131
|
+
return [] if candidates.empty?
|
132
|
+
@last[service] = 0 if @last[service] >= candidates.size
|
133
|
+
candidate = candidates[@last[service]]
|
134
|
+
@last[service] += 1
|
135
|
+
[candidate]
|
136
|
+
end
|
137
|
+
|
138
|
+
# returns all nanites that provide the given service
|
139
|
+
def nanites_providing(service, *tags)
|
140
|
+
nanites.nanites_for(service, *tags)
|
141
|
+
end
|
142
|
+
|
143
|
+
def setup_queues
|
144
|
+
setup_heartbeat_queue
|
145
|
+
setup_registration_queue
|
146
|
+
setup_request_queue
|
147
|
+
end
|
148
|
+
|
149
|
+
def setup_heartbeat_queue
|
150
|
+
handler = lambda do |ping|
|
151
|
+
begin
|
152
|
+
ping = serializer.load(ping)
|
153
|
+
Nanite::Log.debug("got heartbeat from #{ping.identity}") if ping.respond_to?(:identity)
|
154
|
+
handle_ping(ping)
|
155
|
+
rescue Exception => e
|
156
|
+
Nanite::Log.error("Error handling heartbeat: #{e.message}")
|
157
|
+
end
|
158
|
+
end
|
159
|
+
hb_fanout = amq.fanout('heartbeat', :durable => true)
|
160
|
+
if @redis
|
161
|
+
amq.queue("heartbeat").bind(hb_fanout).subscribe &handler
|
162
|
+
else
|
163
|
+
amq.queue("heartbeat-#{identity}", :exclusive => true).bind(hb_fanout).subscribe &handler
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
def setup_registration_queue
|
168
|
+
handler = lambda do |msg|
|
169
|
+
begin
|
170
|
+
msg = serializer.load(msg)
|
171
|
+
Nanite::Log.debug("got registration from #{msg.identity}")
|
172
|
+
register(msg)
|
173
|
+
rescue Exception => e
|
174
|
+
Nanite::Log.error("Error handling registration: #{e.message}")
|
175
|
+
end
|
176
|
+
end
|
177
|
+
reg_fanout = amq.fanout('registration', :durable => true)
|
178
|
+
if @redis
|
179
|
+
amq.queue("registration").bind(reg_fanout).subscribe &handler
|
180
|
+
else
|
181
|
+
amq.queue("registration-#{identity}", :exclusive => true).bind(reg_fanout).subscribe &handler
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
def setup_request_queue
|
186
|
+
handler = lambda do |msg|
|
187
|
+
begin
|
188
|
+
msg = serializer.load(msg)
|
189
|
+
Nanite::Log.debug("got request from #{msg.from} of type #{msg.type}")
|
190
|
+
handle_request(msg)
|
191
|
+
rescue Exception => e
|
192
|
+
Nanite::Log.error("Error handling request: #{e.message}")
|
193
|
+
end
|
194
|
+
end
|
195
|
+
req_fanout = amq.fanout('request', :durable => true)
|
196
|
+
if @redis
|
197
|
+
amq.queue("request").bind(req_fanout).subscribe &handler
|
198
|
+
else
|
199
|
+
amq.queue("request-#{identity}", :exclusive => true).bind(req_fanout).subscribe &handler
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|