isono 0.2.3 → 0.2.6

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/Rakefile CHANGED
@@ -24,7 +24,7 @@ task :gem do
24
24
  s.bindir='bin'
25
25
  s.executables = %w(cli)
26
26
 
27
- s.add_dependency "amqp", "0.7.0"
27
+ s.add_dependency "amqp", "0.7.4"
28
28
  s.add_dependency "eventmachine", "1.0.0.beta.3"
29
29
  s.add_dependency "statemachine", ">= 1.0.0"
30
30
  s.add_dependency "log4r"
data/isono.gemspec CHANGED
@@ -2,35 +2,33 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{isono}
5
- s.version = "0.2.3"
5
+ s.version = "0.2.6"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
- s.authors = ["axsh Ltd.", "Masahiro Fujiwara"]
9
- s.date = %q{2011-06-29}
10
- s.default_executable = %q{cli}
11
- s.email = ["dev@axsh.net", "m-fujiwara@axsh.net"]
12
- s.executables = ["cli"]
13
- s.files = [".gitignore", "LICENSE", "NOTICE", "Rakefile", "bin/cli", "isono.gemspec", "lib/ext/shellwords.rb", "lib/isono.rb", "lib/isono/amqp_client.rb", "lib/isono/daemonize.rb", "lib/isono/event_delegate_context.rb", "lib/isono/event_observable.rb", "lib/isono/logger.rb", "lib/isono/manifest.rb", "lib/isono/messaging_client.rb", "lib/isono/models/event_log.rb", "lib/isono/models/job_state.rb", "lib/isono/models/node_state.rb", "lib/isono/models/resource_instance.rb", "lib/isono/node.rb", "lib/isono/node_modules/base.rb", "lib/isono/node_modules/data_store.rb", "lib/isono/node_modules/event_channel.rb", "lib/isono/node_modules/event_logger.rb", "lib/isono/node_modules/job_channel.rb", "lib/isono/node_modules/job_collector.rb", "lib/isono/node_modules/job_worker.rb", "lib/isono/node_modules/node_collector.rb", "lib/isono/node_modules/node_heartbeat.rb", "lib/isono/node_modules/rpc_channel.rb", "lib/isono/rack.rb", "lib/isono/rack/builder.rb", "lib/isono/rack/data_store.rb", "lib/isono/rack/job.rb", "lib/isono/rack/map.rb", "lib/isono/rack/object_method.rb", "lib/isono/rack/proc.rb", "lib/isono/rack/thread_pass.rb", "lib/isono/resource_manifest.rb", "lib/isono/runner/base.rb", "lib/isono/runner/cli.rb", "lib/isono/runner/rpc_server.rb", "lib/isono/serializer.rb", "lib/isono/thread_pool.rb", "lib/isono/util.rb", "lib/isono/version.rb", "spec/amqp_client_spec.rb", "spec/event_observable_spec.rb", "spec/file_channel_spec.rb", "spec/job_channel_spec.rb", "spec/logger_spec.rb", "spec/manifest_spec.rb", "spec/node_spec.rb", "spec/resource_loader_spec.rb", "spec/rpc_channel_spec.rb", "spec/spec_helper.rb", "spec/thread_pool_spec.rb", "spec/util_spec.rb", "tasks/load_resource_manifest.rake"]
8
+ s.authors = [%q{axsh Ltd.}, %q{Masahiro Fujiwara}]
9
+ s.date = %q{2011-08-23}
10
+ s.email = [%q{dev@axsh.net}, %q{m-fujiwara@axsh.net}]
11
+ s.executables = [%q{cli}]
12
+ s.files = [%q{.gitignore}, %q{LICENSE}, %q{NOTICE}, %q{Rakefile}, %q{bin/cli}, %q{isono.gemspec}, %q{lib/ext/shellwords.rb}, %q{lib/isono.rb}, %q{lib/isono/amqp_client.rb}, %q{lib/isono/daemonize.rb}, %q{lib/isono/event_delegate_context.rb}, %q{lib/isono/event_observable.rb}, %q{lib/isono/logger.rb}, %q{lib/isono/manifest.rb}, %q{lib/isono/messaging_client.rb}, %q{lib/isono/models/event_log.rb}, %q{lib/isono/models/job_state.rb}, %q{lib/isono/models/node_state.rb}, %q{lib/isono/models/resource_instance.rb}, %q{lib/isono/node.rb}, %q{lib/isono/node_modules/base.rb}, %q{lib/isono/node_modules/data_store.rb}, %q{lib/isono/node_modules/event_channel.rb}, %q{lib/isono/node_modules/event_logger.rb}, %q{lib/isono/node_modules/job_channel.rb}, %q{lib/isono/node_modules/job_collector.rb}, %q{lib/isono/node_modules/job_worker.rb}, %q{lib/isono/node_modules/node_collector.rb}, %q{lib/isono/node_modules/node_heartbeat.rb}, %q{lib/isono/node_modules/rpc_channel.rb}, %q{lib/isono/rack.rb}, %q{lib/isono/rack/builder.rb}, %q{lib/isono/rack/data_store.rb}, %q{lib/isono/rack/job.rb}, %q{lib/isono/rack/map.rb}, %q{lib/isono/rack/object_method.rb}, %q{lib/isono/rack/proc.rb}, %q{lib/isono/rack/thread_pass.rb}, %q{lib/isono/resource_manifest.rb}, %q{lib/isono/runner/base.rb}, %q{lib/isono/runner/cli.rb}, %q{lib/isono/runner/rpc_server.rb}, %q{lib/isono/serializer.rb}, %q{lib/isono/thread_pool.rb}, %q{lib/isono/util.rb}, %q{lib/isono/version.rb}, %q{spec/amqp_client_spec.rb}, %q{spec/event_observable_spec.rb}, %q{spec/file_channel_spec.rb}, %q{spec/job_channel_spec.rb}, %q{spec/logger_spec.rb}, %q{spec/manifest_spec.rb}, %q{spec/node_spec.rb}, %q{spec/resource_loader_spec.rb}, %q{spec/rpc_channel_spec.rb}, %q{spec/spec_helper.rb}, %q{spec/thread_pool_spec.rb}, %q{spec/util_spec.rb}, %q{tasks/load_resource_manifest.rake}]
14
13
  s.homepage = %q{http://github.com/axsh/isono}
15
- s.require_paths = ["lib"]
14
+ s.require_paths = [%q{lib}]
16
15
  s.required_ruby_version = Gem::Requirement.new(">= 1.8.7")
17
16
  s.rubyforge_project = %q{isono}
18
- s.rubygems_version = %q{1.3.7}
17
+ s.rubygems_version = %q{1.8.6}
19
18
  s.summary = %q{Messaging and agent fabric}
20
19
 
21
20
  if s.respond_to? :specification_version then
22
- current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
23
21
  s.specification_version = 3
24
22
 
25
23
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
26
- s.add_runtime_dependency(%q<amqp>, ["= 0.7.0"])
24
+ s.add_runtime_dependency(%q<amqp>, ["= 0.7.4"])
27
25
  s.add_runtime_dependency(%q<eventmachine>, ["= 1.0.0.beta.3"])
28
26
  s.add_runtime_dependency(%q<statemachine>, [">= 1.0.0"])
29
27
  s.add_runtime_dependency(%q<log4r>, [">= 0"])
30
28
  s.add_development_dependency(%q<bacon>, [">= 0"])
31
29
  s.add_development_dependency(%q<rake>, [">= 0"])
32
30
  else
33
- s.add_dependency(%q<amqp>, ["= 0.7.0"])
31
+ s.add_dependency(%q<amqp>, ["= 0.7.4"])
34
32
  s.add_dependency(%q<eventmachine>, ["= 1.0.0.beta.3"])
35
33
  s.add_dependency(%q<statemachine>, [">= 1.0.0"])
36
34
  s.add_dependency(%q<log4r>, [">= 0"])
@@ -38,7 +36,7 @@ Gem::Specification.new do |s|
38
36
  s.add_dependency(%q<rake>, [">= 0"])
39
37
  end
40
38
  else
41
- s.add_dependency(%q<amqp>, ["= 0.7.0"])
39
+ s.add_dependency(%q<amqp>, ["= 0.7.4"])
42
40
  s.add_dependency(%q<eventmachine>, ["= 1.0.0.beta.3"])
43
41
  s.add_dependency(%q<statemachine>, [">= 1.0.0"])
44
42
  s.add_dependency(%q<log4r>, [">= 0"])
@@ -4,7 +4,6 @@ require 'thread'
4
4
 
5
5
  require 'eventmachine'
6
6
  require 'amqp'
7
- require 'mq'
8
7
 
9
8
  require 'uri/generic'
10
9
 
@@ -155,7 +154,7 @@ module Isono
155
154
  # @note Do not have to close by user. Channel close is performed
156
155
  # as part of connection close.
157
156
  def create_channel
158
- MQ.new(@amqp_client)
157
+ AMQP::Channel.new(@amqp_client)
159
158
  end
160
159
 
161
160
  # Publish a message to the designated exchange.
@@ -1,7 +1,5 @@
1
1
  # -*- coding: utf-8 -*-
2
2
 
3
- require 'statemachine'
4
-
5
3
  module Isono
6
4
  module NodeModules
7
5
  class JobWorker < Base
@@ -55,14 +53,14 @@ module Isono
55
53
  @thread_pool.pass {
56
54
  begin
57
55
  Thread.current[JOB_CTX_KEY]=job
58
- job.stm.on_start
56
+ job.process_event(:on_start)
59
57
  rpc.request('job-collector', 'update', job.to_hash) { |req|
60
58
  req.oneshot = true
61
59
  }
62
60
  job.run_cb.call
63
- job.stm.on_done
61
+ job.process_event(:on_done)
64
62
  rescue Exception => e
65
- job.stm.on_fail(e)
63
+ job.process_event(:on_fail, e)
66
64
  if job.fail_cb
67
65
  job.fail_cb.arity == 1 ? job.fail_cb.call(e) : job.fail_cb.call
68
66
  end
@@ -109,35 +107,46 @@ module Isono
109
107
 
110
108
  class JobContext < OpenStruct
111
109
  include Logger
112
- attr_reader :stm
113
110
  attr_accessor :run_cb, :fail_cb
111
+ attr_reader :state
114
112
 
115
113
  def initialize()
116
114
  super({:job_id=>Util.gen_id,
117
115
  :parent_job_id=>nil,
118
116
  :started_at=>nil,
119
117
  :finished_at=>nil,
118
+ :finish_status=>nil,
120
119
  })
121
120
 
122
121
  @run_cb=proc{}
123
122
  @fail_cb=nil
124
123
 
125
- @stm = Statemachine.build {
126
- startstate :init
127
- trans :init, :on_start, :running, :on_start
128
- trans :running, :on_done, :done, :on_done
129
- trans :running, :on_fail, :failed, :on_fail
130
- trans :init, :on_fail, :failed, :on_fail
131
- }
132
- @stm.context = self
124
+ @state = :init
133
125
  end
134
126
 
135
- def state
136
- stm.state
127
+ def process_event(ev, *args)
128
+ case [ev,@state]
129
+ when [:on_start, :init]
130
+ @state = :running
131
+ self.started_at = Time.now
132
+ logger.info("Job start #{job_id}")
133
+ when [:on_done, :running]
134
+ @state = :done
135
+ self.finished_at = Time.now
136
+ logger.info("Job complete #{job_id}: #{elapsed_time} sec")
137
+ when [:on_fail, :running]
138
+ @state = :failed
139
+ on_fail(args[0])
140
+ when [:on_fail, :init]
141
+ @state = :failed
142
+ on_fail(args[0])
143
+ else
144
+ raise "Unknown state transition: #{ev}, #{@state}"
145
+ end
137
146
  end
138
147
 
139
148
  def to_hash
140
- @table.dup.merge({:state=>@stm.state})
149
+ @table.dup.merge({:state=>@state})
141
150
  end
142
151
 
143
152
  def elapsed_time
@@ -149,16 +158,6 @@ module Isono
149
158
  end
150
159
 
151
160
  private
152
- def on_start
153
- self.started_at = Time.now
154
- logger.info("Job start #{job_id}")
155
- end
156
-
157
- def on_done
158
- self.finished_at = Time.now
159
- logger.info("Job complete #{job_id}: #{elapsed_time} sec")
160
- end
161
-
162
161
  def on_fail(e)
163
162
  self.finished_at = Time.now
164
163
  logger.error("Job failed #{job_id}: #{e}")
@@ -1,7 +1,6 @@
1
1
  # -*- coding: utf-8 -*-
2
2
 
3
3
  require 'thread'
4
- require 'statemachine'
5
4
  require 'ostruct'
6
5
 
7
6
  module Isono
@@ -16,13 +15,27 @@ module Isono
16
15
  config_section do
17
16
  desc "default timeout duration in second until receive response."
18
17
  timeout_sec (60*3).to_f
18
+ desc "Prefetch size for receiver queue channel"
19
+ receiver_prefetch_size 10
19
20
  end
20
21
 
21
22
  initialize_hook do
22
23
  @active_requests = {}
24
+ @stats = {
25
+ :total_request_count=>0,
26
+ :total_response_count=>0,
27
+ :peak_wait_response_size=>0,
28
+ :send_request_per_sec=>0,
29
+ :receive_response_per_sec=>0,
30
+ :per_sec_last_request_count=>0,
31
+ :per_sec_last_response_count=>0,
32
+ }
23
33
  @endpoints = {}
24
34
  @amq = node.create_channel
25
- @amq.queue("command-recv.#{manifest.node_id}", {:exclusive=>true}).subscribe { |header, data|
35
+ @amq.prefetch(config_section.receiver_prefetch_size.to_i)
36
+ @amq.queue("command-recv.#{manifest.node_id}", {:exclusive=>true}).subscribe(:ack=>true) { |header, data|
37
+ header.ack
38
+ @stats[:total_response_count] += 1
26
39
  req = @active_requests[header.message_id]
27
40
  if req
28
41
  data = Serializer.instance.unmarshal(data)
@@ -48,6 +61,26 @@ module Isono
48
61
  end
49
62
  }
50
63
 
64
+ # Cleanup timed out requests
65
+ EventMachine.add_periodic_timer(10) {
66
+ tnow = Time.now
67
+ @active_requests.each { |k,req|
68
+ next unless req.state == :waiting
69
+ if req.timeout_sec.to_f > 0.0 && req.timeout_sec.to_f > (tnow - req.sent_at)
70
+ @active_requests.delete(k)
71
+ req.error_cb.call(:timeout) if req.error_cb
72
+ end
73
+ }
74
+ }
75
+
76
+ # Update stats
77
+ EventMachine.add_periodic_timer(5) {
78
+ @stats[:send_request_per_sec] = (@stats[:total_request_count] - @stats[:per_sec_last_request_count]) / 5
79
+ @stats[:per_sec_last_request_count] = @stats[:total_request_count]
80
+ @stats[:receive_response_per_sec] = (@stats[:total_response_count] - @stats[:per_sec_last_response_count]) / 5
81
+ @stats[:per_sec_last_response_count] = @stats[:total_response_count]
82
+ }
83
+
51
84
  # RPC endpoint for statistics info of this node.
52
85
  myinstance.register_endpoint("rpc-stats.#{manifest.node_id}", proc { |req, res|
53
86
  case req.command
@@ -169,7 +202,7 @@ module Isono
169
202
  end
170
203
 
171
204
  def response_exchange
172
- self.direct('')
205
+ self.default_exchange
173
206
  end
174
207
  }
175
208
  ch.prefetch(opts[:prefetch].to_i) if opts[:prefetch].to_i > 0
@@ -220,27 +253,23 @@ module Isono
220
253
  # set default timeout if no one updated the initial value.
221
254
  req.timeout_sec = config_section.timeout_sec
222
255
  end
223
-
224
- if req.timeout_sec > 0.0
225
- # register the timeout hook.
226
- req.timer = EventMachine::Timer.new(req.timeout_sec) {
227
- @active_requests.delete req.ticket
228
- req.error_cb.call(:timeout) if req.error_cb
229
- }
230
- end
231
-
256
+
232
257
  req.process_event(:on_ready)
233
258
 
234
259
  EventMachine.schedule {
260
+ @stats[:total_request_count] += 1
261
+ if @stats[:peak_wait_response_size] < @active_requests.size
262
+ @stats[:peak_wait_response_size] = @active_requests.size
263
+ end
235
264
  if !req.oneshot
236
265
  @active_requests[req.ticket] = req
237
266
  end
238
267
 
239
- amq.direct('').publish(Serializer.instance.marshal(req.request_hash),
240
- {:message_id => req.ticket,
241
- :key => endpoint_queue_name(req.endpoint),
242
- :reply_to=>"command-recv.#{manifest.node_id}"}
243
- )
268
+ amq.default_exchange.publish(Serializer.instance.marshal(req.request_hash),
269
+ {:message_id => req.ticket,
270
+ :key => endpoint_queue_name(req.endpoint),
271
+ :reply_to=>"command-recv.#{manifest.node_id}"}
272
+ )
244
273
  req.process_event(:on_sent)
245
274
  }
246
275
  end
@@ -306,7 +335,7 @@ module Isono
306
335
  class RequestContext < OpenStruct
307
336
  # They are not to be appeared in @table so that won't be inspect().
308
337
  attr_reader :error_cb, :success_cb, :progress_cb
309
- attr_accessor :timer
338
+ attr_reader :state
310
339
 
311
340
  def initialize(endpoint, command, args)
312
341
  super({:request=>{
@@ -314,8 +343,6 @@ module Isono
314
343
  :command => command,
315
344
  :args => args
316
345
  },
317
- :endpoint=> endpoint,
318
- :command => command,
319
346
  :ticket => Util.gen_id,
320
347
  :timeout_sec => -1.0,
321
348
  :oneshot => false,
@@ -327,36 +354,40 @@ module Isono
327
354
  @success_cb = nil
328
355
  @progress_cb = nil
329
356
  @error_cb = nil
330
- @timer = nil
331
-
332
- @stm = Statemachine.build {
333
- trans :init, :on_ready, :ready
334
- trans :ready, :on_sent, :waiting, proc {
335
- self.sent_at=Time.now
336
- # freeze request hash not to be modified after sending.
337
- self.request.freeze
338
- }
339
- trans :waiting, :on_received, :waiting
340
- trans :waiting, :on_error, :done, proc {
341
- self.completed_at=Time.now
342
- @timer.cancel if @timer
343
- self.complete_status = :fail
344
- }
345
- trans :waiting, :on_success, :done, proc {
346
- self.completed_at=Time.now
347
- @timer.cancel if @timer
348
- self.complete_status = :success
349
- }
350
- }
351
- @stm.context = self
357
+
358
+ @state = :init
352
359
  end
353
360
 
354
- def state
355
- @stm.state
361
+ def endpoint
362
+ self.request[:endpoint]
363
+ end
364
+
365
+ def command
366
+ self.request[:command]
356
367
  end
357
368
 
358
369
  def process_event(ev, *args)
359
- @stm.process_event(ev, *args)
370
+ case [ev, @state]
371
+ when [:on_ready, :init]
372
+ @state = :ready
373
+ when [:on_sent, :ready]
374
+ @state = :waiting
375
+ self.sent_at=Time.now
376
+ # freeze request hash not to be modified after sending.
377
+ self.request.freeze
378
+ when [:on_received, :waiting]
379
+ @state = :waiting
380
+ when [:on_success, :waiting]
381
+ @state = :done
382
+ self.completed_at=Time.now
383
+ self.complete_status = :success
384
+ when [:on_error, :waiting]
385
+ @state = :done
386
+ self.completed_at=Time.now
387
+ self.complete_status = :fail
388
+ else
389
+ raise "Unknown state transition: #{ev}, #{@state}"
390
+ end
360
391
  end
361
392
 
362
393
  def elapsed_time
@@ -97,7 +97,6 @@ module Isono
97
97
  app = app_builder.call(@builders[:rpc])
98
98
  if app
99
99
  NodeModules::RpcChannel.new(node).register_endpoint(endpoint, Rack.build do
100
- use Rack::ThreadPass
101
100
  run app
102
101
  end
103
102
  )
data/lib/isono/util.rb CHANGED
@@ -33,7 +33,7 @@ module Isono
33
33
  module_function :snake_case
34
34
 
35
35
  def gen_id(str=nil)
36
- Digest::SHA1.hexdigest( (str.nil? ? rand.to_s : str) )
36
+ Digest::SHA1.hexdigest( (str.nil? ? ::Kernel.rand.to_s : str) )
37
37
  end
38
38
  module_function :gen_id
39
39
 
data/lib/isono/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # -*- coding: utf-8 -*-
2
2
 
3
3
  module Isono
4
- VERSION='0.2.3'
4
+ VERSION='0.2.6'
5
5
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: isono
3
3
  version: !ruby/object:Gem::Version
4
- hash: 17
5
- prerelease: false
4
+ hash: 27
5
+ prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 2
9
- - 3
10
- version: 0.2.3
9
+ - 6
10
+ version: 0.2.6
11
11
  platform: ruby
12
12
  authors:
13
13
  - axsh Ltd.
@@ -16,8 +16,7 @@ autorequire:
16
16
  bindir: bin
17
17
  cert_chain: []
18
18
 
19
- date: 2011-06-29 00:00:00 +09:00
20
- default_executable: cli
19
+ date: 2011-08-23 00:00:00 Z
21
20
  dependencies:
22
21
  - !ruby/object:Gem::Dependency
23
22
  name: amqp
@@ -27,12 +26,12 @@ dependencies:
27
26
  requirements:
28
27
  - - "="
29
28
  - !ruby/object:Gem::Version
30
- hash: 3
29
+ hash: 11
31
30
  segments:
32
31
  - 0
33
32
  - 7
34
- - 0
35
- version: 0.7.0
33
+ - 4
34
+ version: 0.7.4
36
35
  type: :runtime
37
36
  version_requirements: *id001
38
37
  - !ruby/object:Gem::Dependency
@@ -181,7 +180,6 @@ files:
181
180
  - spec/thread_pool_spec.rb
182
181
  - spec/util_spec.rb
183
182
  - tasks/load_resource_manifest.rake
184
- has_rdoc: true
185
183
  homepage: http://github.com/axsh/isono
186
184
  licenses: []
187
185
 
@@ -213,7 +211,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
213
211
  requirements: []
214
212
 
215
213
  rubyforge_project: isono
216
- rubygems_version: 1.3.7
214
+ rubygems_version: 1.8.6
217
215
  signing_key:
218
216
  specification_version: 3
219
217
  summary: Messaging and agent fabric