nofxx-nanite 0.4.1.2

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.
Files changed (63) hide show
  1. data/LICENSE +201 -0
  2. data/README.rdoc +430 -0
  3. data/Rakefile +76 -0
  4. data/TODO +24 -0
  5. data/bin/nanite-admin +65 -0
  6. data/bin/nanite-agent +79 -0
  7. data/bin/nanite-mapper +50 -0
  8. data/lib/nanite.rb +74 -0
  9. data/lib/nanite/actor.rb +71 -0
  10. data/lib/nanite/actor_registry.rb +26 -0
  11. data/lib/nanite/admin.rb +138 -0
  12. data/lib/nanite/agent.rb +258 -0
  13. data/lib/nanite/amqp.rb +54 -0
  14. data/lib/nanite/cluster.rb +236 -0
  15. data/lib/nanite/config.rb +111 -0
  16. data/lib/nanite/console.rb +39 -0
  17. data/lib/nanite/daemonize.rb +13 -0
  18. data/lib/nanite/dispatcher.rb +92 -0
  19. data/lib/nanite/identity.rb +16 -0
  20. data/lib/nanite/job.rb +104 -0
  21. data/lib/nanite/local_state.rb +34 -0
  22. data/lib/nanite/log.rb +66 -0
  23. data/lib/nanite/log/formatter.rb +39 -0
  24. data/lib/nanite/mapper.rb +310 -0
  25. data/lib/nanite/mapper_proxy.rb +67 -0
  26. data/lib/nanite/packets.rb +365 -0
  27. data/lib/nanite/pid_file.rb +52 -0
  28. data/lib/nanite/reaper.rb +38 -0
  29. data/lib/nanite/security/cached_certificate_store_proxy.rb +24 -0
  30. data/lib/nanite/security/certificate.rb +55 -0
  31. data/lib/nanite/security/certificate_cache.rb +66 -0
  32. data/lib/nanite/security/distinguished_name.rb +34 -0
  33. data/lib/nanite/security/encrypted_document.rb +46 -0
  34. data/lib/nanite/security/rsa_key_pair.rb +53 -0
  35. data/lib/nanite/security/secure_serializer.rb +68 -0
  36. data/lib/nanite/security/signature.rb +46 -0
  37. data/lib/nanite/security/static_certificate_store.rb +35 -0
  38. data/lib/nanite/security_provider.rb +47 -0
  39. data/lib/nanite/serializer.rb +52 -0
  40. data/lib/nanite/state.rb +164 -0
  41. data/lib/nanite/streaming.rb +125 -0
  42. data/lib/nanite/util.rb +58 -0
  43. data/spec/actor_registry_spec.rb +60 -0
  44. data/spec/actor_spec.rb +77 -0
  45. data/spec/agent_spec.rb +240 -0
  46. data/spec/cached_certificate_store_proxy_spec.rb +34 -0
  47. data/spec/certificate_cache_spec.rb +49 -0
  48. data/spec/certificate_spec.rb +27 -0
  49. data/spec/cluster_spec.rb +485 -0
  50. data/spec/dispatcher_spec.rb +136 -0
  51. data/spec/distinguished_name_spec.rb +24 -0
  52. data/spec/encrypted_document_spec.rb +21 -0
  53. data/spec/job_spec.rb +251 -0
  54. data/spec/local_state_spec.rb +112 -0
  55. data/spec/packet_spec.rb +220 -0
  56. data/spec/rsa_key_pair_spec.rb +33 -0
  57. data/spec/secure_serializer_spec.rb +41 -0
  58. data/spec/serializer_spec.rb +107 -0
  59. data/spec/signature_spec.rb +30 -0
  60. data/spec/spec_helper.rb +33 -0
  61. data/spec/static_certificate_store_spec.rb +30 -0
  62. data/spec/util_spec.rb +63 -0
  63. metadata +131 -0
@@ -0,0 +1,16 @@
1
+ module Nanite
2
+ module Identity
3
+ def self.generate
4
+ values = [
5
+ rand(0x0010000),
6
+ rand(0x0010000),
7
+ rand(0x0010000),
8
+ rand(0x0010000),
9
+ rand(0x0010000),
10
+ rand(0x1000000),
11
+ rand(0x1000000),
12
+ ]
13
+ "%04x%04x%04x%04x%04x%06x%06x" % values
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,104 @@
1
+ module Nanite
2
+ class JobWarden
3
+ attr_reader :serializer, :jobs
4
+
5
+ def initialize(serializer)
6
+ @serializer = serializer
7
+ @jobs = {}
8
+ end
9
+
10
+ def new_job(request, targets, inthandler = nil, blk = nil)
11
+ job = Job.new(request, targets, inthandler, blk)
12
+ jobs[job.token] = job
13
+ job
14
+ end
15
+
16
+ def process(msg)
17
+ if job = jobs[msg.token]
18
+ job.process(msg)
19
+
20
+ if job.intermediate_handler && (job.pending_keys.size > 0)
21
+
22
+ unless job.pending_keys.size == 1
23
+ raise "IntermediateMessages are currently dispatched as they arrive, shouldn't have more than one key in pending_keys: #{job.pending_keys.inspect}"
24
+ end
25
+
26
+ key = job.pending_keys.first
27
+ handler = job.intermediate_handler_for_key(key)
28
+ if handler
29
+ case handler.arity
30
+ when 2
31
+ handler.call(job.intermediate_state[msg.from][key].last, job)
32
+ when 3
33
+ handler.call(key, msg.from, job.intermediate_state[msg.from][key].last)
34
+ when 4
35
+ handler.call(key, msg.from, job.intermediate_state[msg.from][key].last, job)
36
+ end
37
+ end
38
+
39
+ job.reset_pending_intermediate_state_keys
40
+ end
41
+
42
+ if job.completed?
43
+ jobs.delete(job.token)
44
+ if job.completed
45
+ case job.completed.arity
46
+ when 1
47
+ job.completed.call(job.results)
48
+ when 2
49
+ job.completed.call(job.results, job)
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end # JobWarden
56
+
57
+ class Job
58
+ attr_reader :results, :request, :token, :completed, :intermediate_state, :pending_keys, :intermediate_handler
59
+ attr_accessor :targets # This can be updated when a request gets picked up from the offline queue
60
+
61
+ def initialize(request, targets, inthandler = nil, blk = nil)
62
+ @request = request
63
+ @targets = targets
64
+ @token = @request.token
65
+ @results = {}
66
+ @intermediate_handler = inthandler
67
+ @pending_keys = []
68
+ @completed = blk
69
+ @intermediate_state = {}
70
+ end
71
+
72
+ def process(msg)
73
+ case msg
74
+ when Result
75
+ results[msg.from] = msg.results
76
+ targets.delete(msg.from)
77
+ when IntermediateMessage
78
+ intermediate_state[msg.from] ||= {}
79
+ intermediate_state[msg.from][msg.messagekey] ||= []
80
+ intermediate_state[msg.from][msg.messagekey] << msg.message
81
+ @pending_keys << msg.messagekey
82
+ end
83
+ end
84
+
85
+ def intermediate_handler_for_key(key)
86
+ return nil unless @intermediate_handler
87
+ case @intermediate_handler
88
+ when Proc
89
+ @intermediate_handler
90
+ when Hash
91
+ @intermediate_handler[key] || @intermediate_handler['*']
92
+ end
93
+ end
94
+
95
+ def reset_pending_intermediate_state_keys
96
+ @pending_keys = []
97
+ end
98
+
99
+ def completed?
100
+ targets.empty?
101
+ end
102
+ end # Job
103
+
104
+ end # Nanite
@@ -0,0 +1,34 @@
1
+ module Nanite
2
+ class LocalState < ::Hash
3
+ def initialize(hsh={})
4
+ hsh.each do |k,v|
5
+ self[k] = v
6
+ end
7
+ end
8
+
9
+ def all_services
10
+ all(:services)
11
+ end
12
+
13
+ def all_tags
14
+ all(:tags)
15
+ end
16
+
17
+ def nanites_for(service, *tags)
18
+ tags = tags.dup.flatten
19
+ nanites = select { |name, state| state[:services].include?(service) }
20
+ unless tags.empty?
21
+ nanites.select { |a, b| !(b[:tags] & tags).empty? }
22
+ else
23
+ nanites
24
+ end.to_a
25
+ end
26
+
27
+ private
28
+
29
+ def all(key)
30
+ map { |n,s| s[key] }.flatten.uniq.compact
31
+ end
32
+
33
+ end # LocalState
34
+ end # Nanite
@@ -0,0 +1,66 @@
1
+ require 'nanite/config'
2
+ require 'nanite/log/formatter'
3
+ require 'logger'
4
+
5
+ module Nanite
6
+ class Log
7
+
8
+ @logger = nil
9
+
10
+ # Map log levels symbols to values
11
+ LEVELS = { :debug => Logger::DEBUG,
12
+ :info => Logger::INFO,
13
+ :warn => Logger::WARN,
14
+ :error => Logger::ERROR,
15
+ :fatal => Logger::FATAL }
16
+
17
+ class << self
18
+ attr_accessor :logger, :level, :file #:nodoc
19
+
20
+ # Use Nanite::Logger.init when you want to set up the logger manually.
21
+ # If this method is called with no arguments, it will log to STDOUT at the :info level.
22
+ # It also configures the Logger instance it creates to use the custom Nanite::Log::Formatter class.
23
+ def init(identity = nil, path = false)
24
+ if path
25
+ @file = File.join(path, "nanite.#{identity}.log")
26
+ else
27
+ @file = STDOUT
28
+ end
29
+ @logger = Logger.new(file)
30
+ @logger.formatter = Nanite::Log::Formatter.new
31
+ Log.level = :info
32
+ end
33
+
34
+ # Sets the level for the Logger by symbol or by command line argument.
35
+ # Throws an ArgumentError if you feed it a bogus log level (that is not
36
+ # one of :debug, :info, :warn, :error, :fatal or the corresponding strings or a valid Logger level)
37
+ def level=(loglevel)
38
+ init() unless @logger
39
+ lvl = case loglevel
40
+ when String then loglevel.intern
41
+ when Integer then LEVELS.invert[loglevel]
42
+ else loglevel
43
+ end
44
+ unless LEVELS.include?(lvl)
45
+ raise(ArgumentError, 'Log level must be one of :debug, :info, :warn, :error, or :fatal')
46
+ end
47
+ @logger.info("[setup] setting log level to #{lvl.to_s.upcase}")
48
+ @level = lvl
49
+ @logger.level = LEVELS[lvl]
50
+ end
51
+
52
+ # Passes any other method calls on directly to the underlying Logger object created with init. If
53
+ # this method gets hit before a call to Nanite::Logger.init has been made, it will call
54
+ # Nanite::Logger.init() with no arguments.
55
+ def method_missing(method_symbol, *args)
56
+ init unless @logger
57
+ if args.length > 0
58
+ @logger.send(method_symbol, *args)
59
+ else
60
+ @logger.send(method_symbol)
61
+ end
62
+ end
63
+
64
+ end # class << self
65
+ end
66
+ end
@@ -0,0 +1,39 @@
1
+ require 'logger'
2
+ require 'time'
3
+
4
+ module Nanite
5
+ class Log
6
+ class Formatter < Logger::Formatter
7
+ @@show_time = true
8
+
9
+ def self.show_time=(show=false)
10
+ @@show_time = show
11
+ end
12
+
13
+ # Prints a log message as '[time] severity: message' if Nanite::Log::Formatter.show_time == true.
14
+ # Otherwise, doesn't print the time.
15
+ def call(severity, time, progname, msg)
16
+ if @@show_time
17
+ sprintf("[%s] %s: %s\n", time.rfc2822(), severity, msg2str(msg))
18
+ else
19
+ sprintf("%s: %s\n", severity, msg2str(msg))
20
+ end
21
+ end
22
+
23
+ # Converts some argument to a Logger.severity() call to a string. Regular strings pass through like
24
+ # normal, Exceptions get formatted as "message (class)\nbacktrace", and other random stuff gets
25
+ # put through "object.inspect"
26
+ def msg2str(msg)
27
+ case msg
28
+ when ::String
29
+ msg
30
+ when ::Exception
31
+ "#{ msg.message } (#{ msg.class })\n" <<
32
+ (msg.backtrace || []).join("\n")
33
+ else
34
+ msg.inspect
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,310 @@
1
+ module Nanite
2
+ # Mappers are control nodes in nanite clusters. Nanite clusters
3
+ # can follow peer-to-peer model of communication as well as client-server,
4
+ # and mappers are nodes that know who to send work requests to agents.
5
+ #
6
+ # Mappers can reside inside a front end web application written in Merb/Rails
7
+ # and distribute heavy lifting to actors that register with the mapper as soon
8
+ # as they go online.
9
+ #
10
+ # Each mapper tracks nanites registered with it. It periodically checks
11
+ # when the last time a certain nanite sent a heartbeat notification,
12
+ # and removes those that have timed out from the list of available workers.
13
+ # As soon as a worker goes back online again it re-registers itself
14
+ # and the mapper adds it to the list and makes it available to
15
+ # be called again.
16
+ #
17
+ # This makes Nanite clusters self-healing and immune to individual node
18
+ # failures.
19
+ class Mapper
20
+ include AMQPHelper
21
+ include ConsoleHelper
22
+ include DaemonizeHelper
23
+
24
+ attr_reader :cluster, :identity, :job_warden, :options, :serializer, :amq
25
+
26
+ DEFAULT_OPTIONS = COMMON_DEFAULT_OPTIONS.merge({
27
+ :user => 'mapper',
28
+ :identity => Identity.generate,
29
+ :agent_timeout => 15,
30
+ :offline_redelivery_frequency => 10,
31
+ :persistent => false,
32
+ :offline_failsafe => false,
33
+ :requests_failsafe => false,
34
+ :callbacks => {}
35
+ }) unless defined?(DEFAULT_OPTIONS)
36
+
37
+ # Initializes a new mapper and establishes
38
+ # AMQP connection. This must be used inside EM.run block or if EventMachine reactor
39
+ # is already started, for instance, by a Thin server that your Merb/Rails
40
+ # application runs on.
41
+ #
42
+ # Mapper options:
43
+ #
44
+ # identity : identity of this mapper, may be any string
45
+ #
46
+ # format : format to use for packets serialization. Can be :marshal, :json or :yaml or :secure.
47
+ # Defaults to Ruby's Marshall format. For interoperability with
48
+ # AMQP clients implemented in other languages, use JSON.
49
+ #
50
+ # Note that Nanite uses JSON gem,
51
+ # and ActiveSupport's JSON encoder may cause clashes
52
+ # if ActiveSupport is loaded after JSON gem.
53
+ #
54
+ # Also using the secure format requires prior initialization of the serializer, see
55
+ # SecureSerializer.init
56
+ #
57
+ # log_level : the verbosity of logging, can be debug, info, warn, error or fatal.
58
+ #
59
+ # agent_timeout : how long to wait before an agent is considered to be offline
60
+ # and thus removed from the list of available agents.
61
+ #
62
+ # log_dir : log file path, defaults to the current working directory.
63
+ #
64
+ # console : true tells mapper to start interactive console
65
+ #
66
+ # daemonize : true tells mapper to daemonize
67
+ #
68
+ # pid_dir : path to the directory where the agent stores its pid file (only if daemonized)
69
+ # defaults to the root or the current working directory.
70
+ #
71
+ # offline_redelivery_frequency : The frequency in seconds that messages stored in the offline queue will be retrieved
72
+ # for attempted redelivery to the nanites. Default is 10 seconds.
73
+ #
74
+ # persistent : true instructs the AMQP broker to save messages to persistent storage so that they aren't lost when the
75
+ # broker is restarted. Default is false. Can be overriden on a per-message basis using the request and push methods.
76
+ #
77
+ # secure : use Security features of rabbitmq to restrict nanites to themselves
78
+ #
79
+ # prefetch : Sets prefetch (only supported in RabbitMQ >= 1.6)
80
+ # callbacks : A set of callbacks to have code executed on specific events, supported events are :register,
81
+ # :unregister and :timeout. Parameter must be a hash with the corresponding events as keys and
82
+ # a block as value. The block will get the corresponding nanite's identity and a copy of the
83
+ # mapper
84
+ #
85
+ # Connection options:
86
+ #
87
+ # vhost : AMQP broker vhost that should be used
88
+ #
89
+ # user : AMQP broker user
90
+ #
91
+ # pass : AMQP broker password
92
+ #
93
+ # host : host AMQP broker (or node of interest) runs on,
94
+ # defaults to 0.0.0.0
95
+ #
96
+ # port : port AMQP broker (or node of interest) runs on,
97
+ # this defaults to 5672, port used by some widely
98
+ # used AMQP brokers (RabbitMQ and ZeroMQ)
99
+ #
100
+ # @api :public:
101
+ def self.start(options = {})
102
+ mapper = new(options)
103
+ mapper.run
104
+ mapper
105
+ end
106
+
107
+ def initialize(options)
108
+ @options = DEFAULT_OPTIONS.clone.merge(options)
109
+ root = options[:root] || @options[:root]
110
+ custom_config = if root
111
+ file = File.expand_path(File.join(root, 'config.yml'))
112
+ File.exists?(file) ? (YAML.load(IO.read(file)) || {}) : {}
113
+ else
114
+ {}
115
+ end
116
+ options.delete(:identity) unless options[:identity]
117
+ @options.update(custom_config.merge(options))
118
+ @identity = "mapper-#{@options[:identity]}"
119
+ @options[:file_root] ||= File.join(@options[:root], 'files')
120
+ @options.freeze
121
+ end
122
+
123
+ def run
124
+ setup_logging
125
+ @serializer = Serializer.new(@options[:format])
126
+ pid_file = PidFile.new(@identity, @options)
127
+ pid_file.check
128
+ if @options[:daemonize]
129
+ daemonize
130
+ pid_file.write
131
+ at_exit { pid_file.remove }
132
+ else
133
+ trap("INT") {exit}
134
+ end
135
+ @amq = start_amqp(@options)
136
+ @job_warden = JobWarden.new(@serializer)
137
+ setup_cluster
138
+ Nanite::Log.info('[setup] starting mapper')
139
+ setup_queues
140
+ start_console if @options[:console] && !@options[:daemonize]
141
+ end
142
+
143
+ # Make a nanite request which expects a response.
144
+ #
145
+ # ==== Parameters
146
+ # type<String>:: The dispatch route for the request
147
+ # payload<Object>:: Payload to send. This will get marshalled en route
148
+ #
149
+ # ==== Options
150
+ # :selector<Symbol>:: Method for selecting an actor. Default is :least_loaded.
151
+ # :least_loaded:: Pick the nanite which has the lowest load.
152
+ # :all:: Send the request to all nanites which respond to the service.
153
+ # :random:: Randomly pick a nanite.
154
+ # :rr: Select a nanite according to round robin ordering.
155
+ # :target<String>:: Select a specific nanite via identity, rather than using
156
+ # a selector.
157
+ # :offline_failsafe<Boolean>:: Store messages in an offline queue when all
158
+ # the nanites are offline. Messages will be redelivered when nanites come online.
159
+ # Default is false unless the mapper was started with the --offline-failsafe flag.
160
+ # :persistent<Boolean>:: Instructs the AMQP broker to save the message to persistent
161
+ # storage so that it isnt lost when the broker is restarted.
162
+ # Default is false unless the mapper was started with the --persistent flag.
163
+ # :intermediate_handler:: Takes a lambda to call when an IntermediateMessage
164
+ # event arrives from a nanite. If passed a Hash, hash keys should correspond to
165
+ # the IntermediateMessage keys provided by the nanite, and each should have a value
166
+ # that is a lambda/proc taking the parameters specified here. Can supply a key '*'
167
+ # as a catch-all for unmatched keys.
168
+ #
169
+ # ==== Block Parameters for intermediate_handler
170
+ # key<String>:: array of unique keys for which intermediate state has been received
171
+ # since the last call to this block.
172
+ # nanite<String>:: nanite which sent the message.
173
+ # state:: most recently delivered intermediate state for the key provided.
174
+ # job:: (optional) -- if provided, this parameter gets the whole job object, if there's
175
+ # a reason to do more complex work with the job.
176
+ #
177
+ # ==== Block Parameters
178
+ # :results<Object>:: The returned value from the nanite actor.
179
+ #
180
+ # @api :public:
181
+ def request(type, payload = '', opts = {}, &blk)
182
+ request = build_deliverable(Request, type, payload, opts)
183
+ send_request(request, opts, &blk)
184
+ end
185
+
186
+ # Send request with pre-built request instance
187
+ def send_request(request, opts = {}, &blk)
188
+ request.reply_to = identity
189
+ intm_handler = opts.delete(:intermediate_handler)
190
+ targets = cluster.targets_for(request)
191
+ if !targets.empty?
192
+ job = job_warden.new_job(request, targets, intm_handler, blk)
193
+ cluster.route(request, job.targets)
194
+ job
195
+ elsif opts.key?(:offline_failsafe) ? opts[:offline_failsafe] : options[:offline_failsafe]
196
+ job_warden.new_job(request, [], intm_handler, blk)
197
+ cluster.publish(request, 'mapper-offline')
198
+ :offline
199
+ else
200
+ false
201
+ end
202
+ end
203
+
204
+ # Make a nanite request which does not expect a response.
205
+ #
206
+ # ==== Parameters
207
+ # type<String>:: The dispatch route for the request
208
+ # payload<Object>:: Payload to send. This will get marshalled en route
209
+ #
210
+ # ==== Options
211
+ # :selector<Symbol>:: Method for selecting an actor. Default is :least_loaded.
212
+ # :least_loaded:: Pick the nanite which has the lowest load.
213
+ # :all:: Send the request to all nanites which respond to the service.
214
+ # :random:: Randomly pick a nanite.
215
+ # :rr: Select a nanite according to round robin ordering.
216
+ # :offline_failsafe<Boolean>:: Store messages in an offline queue when all
217
+ # the nanites are offline. Messages will be redelivered when nanites come online.
218
+ # Default is false unless the mapper was started with the --offline-failsafe flag.
219
+ # :persistent<Boolean>:: Instructs the AMQP broker to save the message to persistent
220
+ # storage so that it isnt lost when the broker is restarted.
221
+ # Default is false unless the mapper was started with the --persistent flag.
222
+ #
223
+ # @api :public:
224
+ def push(type, payload = '', opts = {})
225
+ push = build_deliverable(Push, type, payload, opts)
226
+ send_push(push, opts)
227
+ end
228
+
229
+ def send_push(push, opts = {})
230
+ targets = cluster.targets_for(push)
231
+ if !targets.empty?
232
+ cluster.route(push, targets)
233
+ true
234
+ elsif opts.key?(:offline_failsafe) ? opts[:offline_failsafe] : options[:offline_failsafe]
235
+ cluster.publish(push, 'mapper-offline')
236
+ :offline
237
+ else
238
+ false
239
+ end
240
+ end
241
+
242
+ private
243
+
244
+ def build_deliverable(deliverable_type, type, payload, opts)
245
+ deliverable = deliverable_type.new(type, payload, nil, opts)
246
+ deliverable.from = identity
247
+ deliverable.token = Identity.generate
248
+ deliverable.persistent = opts.key?(:persistent) ? opts[:persistent] : options[:persistent]
249
+ deliverable
250
+ end
251
+
252
+ def setup_queues
253
+ if amq.respond_to?(:prefetch) && @options.has_key?(:prefetch)
254
+ amq.prefetch(@options[:prefetch])
255
+ end
256
+
257
+ setup_offline_queue
258
+ setup_message_queue
259
+ end
260
+
261
+ def setup_offline_queue
262
+ offline_queue = amq.queue('mapper-offline', :durable => true)
263
+ offline_queue.subscribe(:ack => true) do |info, deliverable|
264
+ deliverable = serializer.load(deliverable)
265
+ targets = cluster.targets_for(deliverable)
266
+ unless targets.empty?
267
+ info.ack
268
+ if deliverable.kind_of?(Request)
269
+ if job = job_warden.jobs[deliverable.token]
270
+ job.targets = targets
271
+ else
272
+ deliverable.reply_to = identity
273
+ job_warden.new_job(deliverable, targets)
274
+ end
275
+ end
276
+ cluster.route(deliverable, targets)
277
+ end
278
+ end
279
+
280
+ EM.add_periodic_timer(options[:offline_redelivery_frequency]) { offline_queue.recover }
281
+ end
282
+
283
+ def setup_message_queue
284
+ amq.queue(identity, :exclusive => true).bind(amq.fanout(identity)).subscribe do |msg|
285
+ begin
286
+ msg = serializer.load(msg)
287
+ Nanite::Log.debug("RECV #{msg.to_s}")
288
+ Nanite::Log.info("RECV #{msg.to_s([:from])}") unless Nanite::Log.level == :debug
289
+ job_warden.process(msg)
290
+ rescue Exception => e
291
+ Nanite::Log.error("RECV [result] #{e.message}")
292
+ end
293
+ end
294
+ end
295
+
296
+ def setup_logging
297
+ log_path = false
298
+ if @options[:daemonize]
299
+ log_path = (@options[:log_dir] || @options[:root] || Dir.pwd)
300
+ end
301
+ Nanite::Log.init(@identity, log_path)
302
+ Nanite::Log.level = @options[:log_level] if @options[:log_level]
303
+ end
304
+
305
+ def setup_cluster
306
+ @cluster = Cluster.new(@amq, @options[:agent_timeout], @options[:identity], @serializer, self, @options[:redis], @options[:callbacks])
307
+ end
308
+ end
309
+ end
310
+