isono 0.2.13 → 0.2.14

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
@@ -16,7 +16,7 @@ task :gem do
16
16
  s.summary = 'Messaging and agent fabric'
17
17
  s.name = 'isono'
18
18
  s.require_path = 'lib'
19
- s.required_ruby_version = '>= 1.8.7'
19
+ s.required_ruby_version = '>= 1.9.2'
20
20
  s.rubyforge_project = 'isono'
21
21
 
22
22
  s.files = `git ls-files -c`.split("\n")
@@ -26,7 +26,6 @@ task :gem do
26
26
 
27
27
  s.add_dependency "amqp", "0.7.4"
28
28
  s.add_dependency "eventmachine", "1.0.0.beta.4"
29
- s.add_dependency "statemachine", ">= 1.0.0"
30
29
  s.add_dependency "log4r"
31
30
 
32
31
  s.add_development_dependency 'bacon'
@@ -2,17 +2,17 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = "isono"
5
- s.version = "0.2.13"
5
+ s.version = "0.2.14"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["axsh Ltd.", "Masahiro Fujiwara"]
9
- s.date = "2012-08-08"
9
+ s.date = "2012-08-30"
10
10
  s.email = ["dev@axsh.net", "m-fujiwara@axsh.net"]
11
11
  s.executables = ["cli"]
12
12
  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/sequel.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"]
13
13
  s.homepage = "http://github.com/axsh/isono"
14
14
  s.require_paths = ["lib"]
15
- s.required_ruby_version = Gem::Requirement.new(">= 1.8.7")
15
+ s.required_ruby_version = Gem::Requirement.new(">= 1.9.2")
16
16
  s.rubyforge_project = "isono"
17
17
  s.rubygems_version = "1.8.24"
18
18
  s.summary = "Messaging and agent fabric"
@@ -23,14 +23,12 @@ Gem::Specification.new do |s|
23
23
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
24
24
  s.add_runtime_dependency(%q<amqp>, ["= 0.7.4"])
25
25
  s.add_runtime_dependency(%q<eventmachine>, ["= 1.0.0.beta.4"])
26
- s.add_runtime_dependency(%q<statemachine>, [">= 1.0.0"])
27
26
  s.add_runtime_dependency(%q<log4r>, [">= 0"])
28
27
  s.add_development_dependency(%q<bacon>, [">= 0"])
29
28
  s.add_development_dependency(%q<rake>, [">= 0"])
30
29
  else
31
30
  s.add_dependency(%q<amqp>, ["= 0.7.4"])
32
31
  s.add_dependency(%q<eventmachine>, ["= 1.0.0.beta.4"])
33
- s.add_dependency(%q<statemachine>, [">= 1.0.0"])
34
32
  s.add_dependency(%q<log4r>, [">= 0"])
35
33
  s.add_dependency(%q<bacon>, [">= 0"])
36
34
  s.add_dependency(%q<rake>, [">= 0"])
@@ -38,7 +36,6 @@ Gem::Specification.new do |s|
38
36
  else
39
37
  s.add_dependency(%q<amqp>, ["= 0.7.4"])
40
38
  s.add_dependency(%q<eventmachine>, ["= 1.0.0.beta.4"])
41
- s.add_dependency(%q<statemachine>, [">= 1.0.0"])
42
39
  s.add_dependency(%q<log4r>, [">= 0"])
43
40
  s.add_dependency(%q<bacon>, [">= 0"])
44
41
  s.add_dependency(%q<rake>, [">= 0"])
@@ -7,7 +7,7 @@ module Isono
7
7
  class JobState < Sequel::Model
8
8
  include Logger
9
9
  plugin :schema
10
- plugin :hook_class_methods
10
+ plugin :timestamps, :update_on_create=>true
11
11
 
12
12
  set_schema {
13
13
  primary_key :id, :type => Integer, :auto_increment=>true, :unsigned=>true
@@ -25,13 +25,6 @@ module Isono
25
25
  index :job_id, {:unique=>true}
26
26
  }
27
27
 
28
- before_create(:set_created_at) do
29
- self.created_at = self.updated_at= Time.now
30
- end
31
- before_update(:set_updated_at) do
32
- self.updated_at= Time.now
33
- end
34
-
35
28
  end
36
29
  end
37
30
  end
@@ -1,14 +1,13 @@
1
1
  # -*- coding: utf-8 -*-
2
2
 
3
3
  require 'sequel/model'
4
- require 'statemachine'
5
4
 
6
5
  module Isono
7
6
  module Models
8
7
  class NodeState < Sequel::Model
9
8
  include Logger
10
9
  plugin :schema
11
- plugin :hook_class_methods
10
+ plugin :timestamps, :update_on_create=>true
12
11
 
13
12
  set_schema {
14
13
  primary_key :id, :type => Integer, :auto_increment=>true, :unsigned=>true
@@ -21,48 +20,28 @@ module Isono
21
20
  index :node_id, {:unique=>true}
22
21
  }
23
22
 
24
- before_create(:set_created_at) do
25
- self.updated_at = self.created_at = Time.now
23
+ def after_initialize
24
+ self[:state] = :init
26
25
  end
27
- before_update(:set_updated_at) do
28
- self.updated_at = Time.now
29
- end
30
-
31
-
32
- def state_machine
33
- model = self
34
- st = Statemachine.build do
35
- startstate :init
36
- trans :init, :on_ping, :online, proc {model.last_ping_at = Time.now}
37
- trans :online, :on_timeout, :timeout
38
- trans :timeout, :on_ping, :online, proc {model.last_ping_at = Time.now}
39
- trans :online, :on_unmonitor, :offline
40
- trans :timeout, :on_unmonitor, :offline
41
- # do nothing on transition from and to the same state
42
- trans :online, :on_ping, :online, proc {model.last_ping_at = Time.now}
43
- trans :timeout, :on_timeout, :timeout
44
-
45
- on_entry_of :online, proc {
46
- model.state = :online
47
- }
48
- on_entry_of :timeout, proc {
49
- model.state = :timeout
50
- }
51
- on_entry_of :offline, proc {
52
- model.state = :offline
53
- }
54
- end
55
-
56
- if self[:state]
57
- if st.has_state(self[:state].to_sym)
58
- st.state = self[:state].to_sym
59
- else
60
- raise "Unknown state: #{self[:state]}"
61
- end
26
+
27
+ def process_event(ev, *args)
28
+ case [ev, self.state.to_sym]
29
+ when [:on_ping, :online], [:on_ping, :init], [:on_ping, :timeout]
30
+ self.state = :online
31
+ self.last_ping_at = Time.now
32
+ when [:on_unmonitor, :online]
33
+ self.state = :offline
34
+ when [:on_unmonitor, :timeout]
35
+ self.state = :offline
36
+ when [:on_unmonitor, :init]
37
+ self.state = :offline
38
+ when [:on_timeout, :online], [:on_timeout, :timeout]
39
+ self.state = :timeout
40
+ when [:on_timeout, :init]
41
+ # Do nothing
62
42
  else
63
- st.reset
43
+ raise "Unknown state transition: #{ev}, #{self.state}"
64
44
  end
65
- st
66
45
  end
67
46
 
68
47
  end
@@ -12,6 +12,7 @@ module Isono
12
12
 
13
13
  raise "Module initializer_hook is not run yet" if self.value_object.nil?
14
14
  value_object.copy_instance_variables(self)
15
+ after_initialize
15
16
  end
16
17
 
17
18
  # Delegate methods used in subclass frequently.
@@ -75,6 +76,10 @@ module Isono
75
76
  @node_hooks = {}
76
77
  }
77
78
  end
79
+
80
+ protected
81
+ def after_initialize
82
+ end
78
83
 
79
84
  end
80
85
  end
@@ -72,10 +72,15 @@ module Isono
72
72
 
73
73
  def cancel(job_id)
74
74
  end
75
-
75
+
76
76
  def register_endpoint(endpoint, app, opts={})
77
- opts = {:concurrency=>config_section.concurrency}.merge(opts)
78
- rpc.register_endpoint("job.#{endpoint}", Rack::Job.new(app, JobWorker.new(node)), {:prefetch=>opts[:concurrency]})
77
+ raise ArgumentError unless endpoint.is_a?(String)
78
+ raise ArgumentError unless app.respond_to?(:call)
79
+ opts = {
80
+ :concurrency=>config_section.concurrency,
81
+ :thread_pool => nil,
82
+ }.merge(opts)
83
+ rpc.register_endpoint("job.#{endpoint}", Rack::Job.new(app, JobWorker.new(@node, opts[:thread_pool])), {:prefetch=>opts[:concurrency]})
79
84
  end
80
85
 
81
86
  private
@@ -14,7 +14,7 @@ module Isono
14
14
  end
15
15
 
16
16
  initialize_hook do
17
- @thread_pool = ThreadPool.new(config_section.concurrency.to_i, 'JobWorker')
17
+ @default_thread_pool = ThreadPool.new(config_section.concurrency.to_i, 'JobWorker')
18
18
  @active_jobs = {}
19
19
 
20
20
  RpcChannel.new(node).register_endpoint("job-stats.#{node.node_id}", proc { |req, res|
@@ -31,6 +31,12 @@ module Isono
31
31
  @thread_pool.shutdown
32
32
  end
33
33
 
34
+ def initialize(node, thread_pool=nil)
35
+ super(node)
36
+ raise ArgumentError unless thread_pool.nil? || thread_pool.is_a?(ThreadPool)
37
+ @thread_pool = thread_pool || @default_thread_pool
38
+ end
39
+
34
40
  # Start a new long term job.
35
41
  #
36
42
  # @yield The block to setup JobContext object.
@@ -30,22 +30,20 @@ module Isono
30
30
  # http://www.mail-archive.com/sqlite-users@sqlite.org/msg03328.html
31
31
  # TODO: paging support for the large result set.
32
32
  Models::NodeState.dataset.all.each { |row|
33
-
34
- sm = row.state_machine
35
- next if sm.state == :offline
33
+ next if row.state == :offline
36
34
 
37
35
  diff_time = Time.now - row[:last_ping_at]
38
- if sm.state != :timeout && diff_time > config_section.timeout_sec
39
- sm.on_timeout
36
+ if row.state != :timeout && diff_time > config_section.timeout_sec
37
+ row.process_event(:on_timeout)
40
38
  row.save_changes
41
39
  event.publish('node_collector/timedout', :args=>[row.values])
42
40
  end
43
41
 
44
42
  if diff_time > config_section.kill_sec
45
- sm.on_unmonitor
43
+ row.process_event(:on_unmonitor)
46
44
 
47
45
  event.publish('node_collector/killed', :args=>[row.values])
48
- row.delete
46
+ row.destroy
49
47
  end
50
48
  }
51
49
  }
@@ -71,7 +69,7 @@ module Isono
71
69
  event = EventChannel.new(node)
72
70
 
73
71
  a = Models::NodeState.find(:node_id=>node_id) || Models::NodeState.new(:node_id=>node_id)
74
- a.state_machine.on_ping
72
+ a.process_event(:on_ping)
75
73
  if a.new?
76
74
  a.boot_token = boot_token
77
75
  a.save
@@ -164,7 +164,7 @@ module Isono
164
164
  # :prefetch
165
165
  def register_endpoint(endpoint, app, opts={})
166
166
  raise TypeError unless app.respond_to?(:call)
167
- opts = {:exclusive=>true, :prefetch=>0}.merge(opts)
167
+ opts = {:exclusive=>true, :prefetch=>1}.merge(opts)
168
168
 
169
169
  # create receive queue for new RPC endpoint.
170
170
  endpoint_proc = proc { |header, data|
@@ -190,13 +190,8 @@ module Isono
190
190
 
191
191
 
192
192
  EventMachine.schedule {
193
- ch = if opts[:prefetch].to_i > 0
194
- # create per endpoint channel
195
- node.create_channel
196
- else
197
- # use default channel
198
- @amq
199
- end
193
+ ch = node.create_channel
194
+
200
195
  ch.instance_eval %Q{
201
196
  def endpoint_queue
202
197
  self.queue("isono.rpc.endpoint.#{endpoint}", {:exclusive=>false, :auto_delete=>true})
@@ -44,6 +44,7 @@ module Rack
44
44
 
45
45
  def initialize(app, job_worker)
46
46
  super(app)
47
+ raise ArgumentError unless job_worker.respond_to?(:start)
47
48
  @job_worker = job_worker
48
49
  end
49
50
 
@@ -80,36 +80,44 @@ module Isono
80
80
  add(:rpc, command, &blk)
81
81
  end
82
82
 
83
- def build(endpoint, node)
84
- helper_context = self.new(node)
85
-
86
- app_builder = lambda { |builders|
87
- unless builders.empty?
88
- map_app = Rack::Map.new
89
- builders.each { |b|
90
- b.call(map_app, helper_context)
91
- }
92
- map_app
93
- end
94
- }
83
+ def concurrency(num)
84
+ raise ArgumentError unless num.is_a?(Fixnum)
85
+ @concurrency = num
86
+ end
95
87
 
88
+ def job_thread_pool(thread_pool)
89
+ raise ArgumentError unless thread_pool.is_a?(Isono::ThreadPool)
90
+ @job_thread_pool = thread_pool
91
+ end
92
+
93
+ def setup(endpoint_name, builder)
94
+ app_builder = lambda { |builder_hooks|
95
+ return nil if builder_hooks.empty?
96
+ map_app = Rack::Map.new
97
+ builder_hooks.each { |b|
98
+ b.call(map_app, builder)
99
+ }
100
+ map_app
101
+ }
102
+
96
103
  app = app_builder.call(@builders[:job])
97
104
  if app
98
- NodeModules::JobChannel.new(node).register_endpoint(endpoint, Rack.build do
99
- run app
100
- end)
105
+ builder.job_channel.register_endpoint(endpoint_name,
106
+ Rack.build do
107
+ run app
108
+ end,
109
+ {:concurrency=>@concurrency,
110
+ :thread_pool=>@job_thread_pool})
101
111
  end
102
112
 
103
113
  app = app_builder.call(@builders[:rpc])
104
114
  if app
105
- NodeModules::RpcChannel.new(node).register_endpoint(endpoint, Rack.build do
106
- run app
107
- end
108
- )
115
+ builder.rpc_channel.register_endpoint(endpoint, Rack.build do
116
+ run app
117
+ end, {:prefetch=>@concurrency})
109
118
  end
110
119
  end
111
120
 
112
-
113
121
  protected
114
122
  def add(type, command, &blk)
115
123
  @builders[type] << lambda { |rack_map, ctx|
@@ -121,15 +129,33 @@ module Isono
121
129
  def self.inherited(klass)
122
130
  klass.class_eval {
123
131
  @builders = {:job=>[], :rpc=>[]}
132
+ @concurrency = 1
133
+ @job_thread_pool = nil
124
134
  extend BuildMethods
125
135
  }
126
136
  end
127
137
 
128
138
  def initialize(node)
129
139
  @node = node
140
+ @rpc_channel = NodeModules::RpcChannel.new(@node)
141
+ @job_channel = NodeModules::JobChannel.new(@node)
142
+ after_initialize
143
+ end
144
+
145
+ def job_channel
146
+ @job_channel
147
+ end
148
+ alias :job :job_channel
149
+
150
+ def rpc_channel
151
+ @rpc_channel
152
+ end
153
+ alias :rpc :rpc_channel
154
+
155
+ protected
156
+ def after_initialize
130
157
  end
131
158
  end
132
-
133
159
 
134
160
  DEFAULT_MANIFEST = Manifest.new(Dir.pwd) do
135
161
  load_module NodeModules::EventChannel
@@ -147,13 +173,15 @@ module Isono
147
173
  class Server < Base
148
174
  def initialize(builder_block)
149
175
  super()
176
+ @endpoints = {}
150
177
  @builder_block = builder_block
151
178
  end
152
179
 
153
180
  # DSL method
154
- def endpoint(endpoint, builder)
155
- raise TypeError unless builder.respond_to?(:build)
156
- builder.build(endpoint, @node)
181
+ def endpoint(endpoint, builder_class, *args)
182
+ raise ArgumentError unless builder_class.is_a?(Class) && builder_class < EndpointBuilder
183
+ raise "Duplicate endpoint name: #{endpoint}" if @endpoints[endpoint.to_s]
184
+ @endpoints[endpoint.to_s] = builder_class.new(@node, *args)
157
185
  end
158
186
 
159
187
  protected
@@ -161,6 +189,8 @@ module Isono
161
189
  @node = Isono::Node.new(manifest)
162
190
  @node.connect(@options[:amqp_server_uri]) do
163
191
  self.instance_eval(&@builder_block) if @builder_block
192
+
193
+ @endpoints.each {|name, i| i.class.setup(name, i) }
164
194
  end
165
195
  end
166
196
 
@@ -1,5 +1,5 @@
1
1
  # -*- coding: utf-8 -*-
2
2
 
3
3
  module Isono
4
- VERSION='0.2.13'
4
+ VERSION='0.2.14'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: isono
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.13
4
+ version: 0.2.14
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2012-08-08 00:00:00.000000000 Z
13
+ date: 2012-08-30 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: amqp
@@ -44,22 +44,6 @@ dependencies:
44
44
  - - '='
45
45
  - !ruby/object:Gem::Version
46
46
  version: 1.0.0.beta.4
47
- - !ruby/object:Gem::Dependency
48
- name: statemachine
49
- requirement: !ruby/object:Gem::Requirement
50
- none: false
51
- requirements:
52
- - - ! '>='
53
- - !ruby/object:Gem::Version
54
- version: 1.0.0
55
- type: :runtime
56
- prerelease: false
57
- version_requirements: !ruby/object:Gem::Requirement
58
- none: false
59
- requirements:
60
- - - ! '>='
61
- - !ruby/object:Gem::Version
62
- version: 1.0.0
63
47
  - !ruby/object:Gem::Dependency
64
48
  name: log4r
65
49
  requirement: !ruby/object:Gem::Requirement
@@ -188,7 +172,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
188
172
  requirements:
189
173
  - - ! '>='
190
174
  - !ruby/object:Gem::Version
191
- version: 1.8.7
175
+ version: 1.9.2
192
176
  required_rubygems_version: !ruby/object:Gem::Requirement
193
177
  none: false
194
178
  requirements: