isono 0.2.13 → 0.2.14

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