isono 0.2.3 → 0.2.6

Sign up to get free protection for your applications and to get access to all the features.
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