wakame 0.5.0 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (111) hide show
  1. data/History.txt +4 -0
  2. data/LICENSE +202 -0
  3. data/Rakefile +11 -12
  4. data/VERSION +1 -1
  5. data/app_generators/wakame/templates/bin/wakame-agent +1 -1
  6. data/app_generators/wakame/templates/bin/wakame-master +1 -1
  7. data/app_generators/wakame/templates/config/cluster.rb +32 -24
  8. data/app_generators/wakame/templates/config/init.d/centos/wakame-agent +40 -0
  9. data/app_generators/wakame/templates/config/init.d/centos/wakame-master +40 -0
  10. data/app_generators/wakame/templates/config/init.d/wakame-master +1 -1
  11. data/lib/ext/eventmachine.rb +5 -5
  12. data/lib/wakame.rb +12 -0
  13. data/lib/wakame/action.rb +10 -11
  14. data/lib/wakame/actions/deploy_application.rb +61 -0
  15. data/lib/wakame/actions/deploy_config.rb +1 -3
  16. data/lib/wakame/actions/freeze_cluster.rb +15 -0
  17. data/lib/wakame/actions/launch_cluster.rb +1 -3
  18. data/lib/wakame/actions/launch_vm.rb +1 -1
  19. data/lib/wakame/actions/migrate_service.rb +4 -3
  20. data/lib/wakame/actions/notify_child_changed.rb +3 -6
  21. data/lib/wakame/actions/notify_parent_changed.rb +4 -7
  22. data/lib/wakame/actions/propagate_resource.rb +1 -3
  23. data/lib/wakame/actions/propagate_service.rb +1 -3
  24. data/lib/wakame/actions/register_agent.rb +43 -0
  25. data/lib/wakame/actions/reload_service.rb +2 -2
  26. data/lib/wakame/actions/shutdown_cluster.rb +4 -6
  27. data/lib/wakame/actions/shutdown_vm.rb +27 -6
  28. data/lib/wakame/actions/start_service.rb +40 -32
  29. data/lib/wakame/actions/stop_service.rb +8 -10
  30. data/lib/wakame/actions/unfreeze_cluster.rb +15 -0
  31. data/lib/wakame/actor.rb +2 -5
  32. data/lib/wakame/actor/deploy.rb +110 -0
  33. data/lib/wakame/actor/monitor.rb +14 -0
  34. data/lib/wakame/actor/s3fs.rb +45 -0
  35. data/lib/wakame/actor/service_monitor.rb +0 -17
  36. data/lib/wakame/actor/system.rb +5 -1
  37. data/lib/wakame/agent.rb +29 -179
  38. data/lib/wakame/agent_manager.rb +11 -0
  39. data/lib/wakame/agent_managers/actor_manager.rb +101 -0
  40. data/lib/wakame/agent_managers/monitor_manager.rb +48 -0
  41. data/lib/wakame/command.rb +4 -7
  42. data/lib/wakame/command/actor.rb +9 -12
  43. data/lib/wakame/command/agent_status.rb +2 -2
  44. data/lib/wakame/command/control_service.rb +66 -0
  45. data/lib/wakame/command/deploy_application.rb +18 -0
  46. data/lib/wakame/command/deploy_config.rb +16 -0
  47. data/lib/wakame/command/launch_cluster.rb +1 -1
  48. data/lib/wakame/command/launch_vm.rb +1 -1
  49. data/lib/wakame/command/propagate_resource.rb +1 -1
  50. data/lib/wakame/command/propagate_service.rb +5 -3
  51. data/lib/wakame/command/reload_service.rb +1 -1
  52. data/lib/wakame/command/shutdown_cluster.rb +1 -1
  53. data/lib/wakame/command/shutdown_vm.rb +37 -11
  54. data/lib/wakame/command/start_service.rb +1 -1
  55. data/lib/wakame/command/status.rb +6 -4
  56. data/lib/wakame/command/stop_service.rb +1 -1
  57. data/lib/wakame/configuration.rb +5 -0
  58. data/lib/wakame/event.rb +85 -33
  59. data/lib/wakame/event_dispatcher.rb +2 -2
  60. data/lib/wakame/initializer.rb +97 -31
  61. data/lib/wakame/master.rb +23 -346
  62. data/lib/wakame/master_manager.rb +11 -0
  63. data/lib/wakame/master_managers/action_manager.rb +321 -0
  64. data/lib/wakame/master_managers/agent_monitor.rb +166 -0
  65. data/lib/wakame/master_managers/cluster_manager.rb +176 -0
  66. data/lib/wakame/master_managers/command_queue.rb +133 -0
  67. data/lib/wakame/models/agent_pool.rb +113 -0
  68. data/lib/wakame/models/application_repository.rb +34 -0
  69. data/lib/wakame/models/object_store.rb +32 -0
  70. data/lib/wakame/models/service_cluster_pool.rb +36 -0
  71. data/lib/wakame/monitor.rb +3 -6
  72. data/lib/wakame/monitor/agent.rb +9 -6
  73. data/lib/wakame/monitor/service.rb +56 -29
  74. data/lib/wakame/runner/administrator_command.rb +210 -24
  75. data/lib/wakame/runner/agent.rb +2 -0
  76. data/lib/wakame/runner/master.rb +2 -1
  77. data/lib/wakame/service.rb +140 -130
  78. data/lib/wakame/status_db.rb +101 -121
  79. data/lib/wakame/util.rb +26 -15
  80. data/tests/setup_master.rb +1 -0
  81. data/tests/test_master.rb +0 -2
  82. data/tests/test_model_agent_pool.rb +21 -0
  83. data/tests/test_service.rb +14 -8
  84. data/tests/test_status_db.rb +2 -0
  85. data/tests/test_util.rb +12 -1
  86. data/wakame_generators/resource/templates/apache_app/apache_app.rb +20 -11
  87. data/wakame_generators/resource/templates/apache_app/conf/vh/aaa.test.conf +1 -1
  88. data/wakame_generators/resource/templates/apache_lb/apache_lb.rb +7 -7
  89. data/wakame_generators/resource/templates/apache_lb/conf/system-lb.conf +6 -4
  90. data/wakame_generators/resource/templates/apache_www/apache_www.rb +15 -13
  91. data/wakame_generators/resource/templates/ec2_elastic_ip/ec2_elastic_ip.rb +17 -17
  92. data/wakame_generators/resource/templates/ec2_elb/ec2_elb.rb +22 -15
  93. data/wakame_generators/resource/templates/mongodb/conf/mongodb.conf +95 -0
  94. data/wakame_generators/resource/templates/mongodb/init.d/mongodb +244 -0
  95. data/wakame_generators/resource/templates/mongodb/mongodb.rb +64 -0
  96. data/wakame_generators/resource/templates/mysql_master/mysql_master.rb +17 -21
  97. data/wakame_generators/resource/templates/nginx/conf/nginx.conf +4 -0
  98. data/wakame_generators/resource/templates/nginx/conf/vh/ec2_elb_common.conf +19 -0
  99. data/wakame_generators/resource/templates/nginx/init.d/nginx +6 -0
  100. data/wakame_generators/resource/templates/nginx/init.d/spawn-fcgi +46 -0
  101. data/wakame_generators/resource/templates/nginx/nginx.rb +15 -10
  102. data/wakame_generators/resource/templates/nginx_passenger/conf/nginx-passenger.conf +39 -0
  103. data/wakame_generators/resource/templates/nginx_passenger/conf/vh/ec2_elb_common.conf +10 -0
  104. data/wakame_generators/resource/templates/nginx_passenger/init.d/nginx-passenger +70 -0
  105. data/wakame_generators/resource/templates/nginx_passenger/nginx_passenger.rb +71 -0
  106. data/wakame_generators/resource/templates/s3fs/s3fs.rb +24 -0
  107. metadata +195 -74
  108. data/lib/wakame/action_manager.rb +0 -303
  109. data/lib/wakame/command/clone_service.rb +0 -12
  110. data/lib/wakame/command_queue.rb +0 -135
  111. data/lib/wakame/vm_manipulator.rb +0 -187
@@ -1,5 +1,6 @@
1
1
 
2
2
  require 'thread'
3
+ require 'timeout'
3
4
 
4
5
  module Wakame
5
6
  module StatusDB
@@ -12,28 +13,41 @@ module Wakame
12
13
  end
13
14
  end
14
15
 
15
- def self.barrier(&blk)
16
+ def self.barrier(tout=60*2, &blk)
16
17
  abort "Cant use barrier() in side of the EventMachine thread." if Kernel.const_defined?(:EventMachine) && ::EventMachine.reactor_thread?
17
18
 
18
19
  if Thread.current == WorkerThread.worker_thread
19
20
  return blk.call
20
21
  end
21
22
 
22
- @q ||= ::Queue.new
23
+ Wakame.log.debug("StatusDB.barrier: Called at #{caller(1)[0..1].inspect} on the thread #{Thread.current}.")
24
+
25
+ q = ::Queue.new
23
26
  time_start = ::Time.now
24
27
 
25
28
  self.pass {
26
29
  begin
27
30
  res = blk.call
28
- @q << [true, res]
31
+ q << [true, res]
29
32
  rescue => e
30
- @q << [false, e]
33
+ q << [false, e]
31
34
  end
32
35
  }
33
-
34
- res = @q.shift
36
+
37
+ res = nil
38
+ begin
39
+ timeout(tout) do
40
+ res = q.shift
41
+ end
42
+ rescue Timeout::Error => e
43
+ Wakame.log.error("WorkerThread.queue.size=#{WorkerThread.queue.size}")
44
+ Wakame.log.error(e)
45
+ raise e
46
+ end
47
+
35
48
  time_elapsed = ::Time.now - time_start
36
49
  Wakame.log.debug("#{self}.barrier: Elapsed time for #{blk}: #{time_elapsed} sec") if time_elapsed > 0.05
50
+
37
51
  if res[0] == false && res[1].is_a?(Exception)
38
52
  raise res[1]
39
53
  end
@@ -56,8 +70,11 @@ module Wakame
56
70
  if @thread.nil?
57
71
  @thread = Thread.new {
58
72
  while blk = queue.deq
73
+ Wakame.log.debug("#{self}: Queued Jobs: #{queue.size}") if queue.size > 0
59
74
  begin
60
- blk.call
75
+ Wakame::Models::ObjectStore.db.transaction {
76
+ blk.call
77
+ }
61
78
  rescue => e
62
79
  Wakame.log.error("#{self.class}: #{e}")
63
80
  Wakame.log.error(e)
@@ -70,7 +87,7 @@ module Wakame
70
87
 
71
88
  def self.terminate
72
89
  if self.queue.size > 0
73
- Wakame.log.warn("#{self.class}: #{self.class.queue.size} of non-processed reqs are going to be ignored to shutdown the worker thread.")
90
+ Wakame.log.warn("#{self.class}: #{self.class.queue.size} of queued reqs are going to be ignored to shutdown the worker thread.")
74
91
  self.queue.clear
75
92
  end
76
93
  self.worker_thread.kill if !self.worker_thread.nil? && self.worker_thread.alive?
@@ -83,72 +100,20 @@ module Wakame
83
100
  end
84
101
 
85
102
  class SequelAdapter
86
- DATA_FORMAT_VERSION='0.4'
87
103
 
88
104
  def initialize
89
- require 'sequel/core'
90
- require 'sequel/model'
91
-
92
- #@db = Sequel.connect(Wakame.config.status_db_dsn, {:logger=>Wakame.log})
93
- @db = Sequel.connect(Wakame.config.status_db_dsn)
94
-
95
- if [:metadata, :model_stores].all?{ |i| @db.table_exists?(i) }
96
- m = @db[:metadata].where(:id=>1).first
97
-
98
- unless m && m[:version] == DATA_FORMAT_VERSION
99
- setup_store
100
- end
101
-
102
- else
103
- setup_store
104
- end
105
-
106
- # Generate Sequel::Model class dynamically.
107
- # This is same as below:
108
- # class ModelStore < Sequel::Model
109
- # unrestrict_primary_key
110
- # end
111
- @model_class = Class.new(Sequel::Model(:model_stores)) { |klass|
112
- klass.unrestrict_primary_key
113
- }
114
- @model_class.plugin :schema
115
- @model_class.plugin :hook_class_methods
116
- @model_class.class_eval {
117
- before_create(:set_created_at) do
118
- self.updated_at = self.created_at = Time.now
119
- end
120
- before_update(:set_updated_at) do
121
- self.updated_at = Time.now
122
- end
123
- }
124
- # @model_class.plugin :caching, store
125
- end
126
-
127
- def setup_store
128
- @db.drop_table :metadata rescue nil
129
- @db.create_table? :metadata do
130
- primary_key :id
131
- column :version, :string
132
- column :created_at, :datetime
133
- end
134
-
135
- @db[:metadata].insert(:version=>DATA_FORMAT_VERSION, :created_at=>Time.now)
136
-
137
- @db.drop_table :model_stores rescue nil
138
- @db.create_table? :model_stores do
139
- primary_key :id, :string, :size=>50, :auto_increment=>false
140
- column :class_type, :string
141
- column :dump, :text
142
- column :created_at, :datetime
143
- column :updated_at, :datetime
144
- end
105
+ @model_class = Wakame::Models::ObjectStore
145
106
  end
146
107
 
147
- def find(id, &blk)
108
+ def find(id)
109
+ Wakame.log.debug("StatusDB.find(#{id}) called by #{Thread.current.to_s}") unless Thread.current == WorkerThread.worker_thread
148
110
  m = @model_class[id]
149
111
  if m
150
112
  hash = eval(m[:dump])
151
- blk.call(id, hash)
113
+ hash[AttributeHelper::CLASS_TYPE_KEY]=m.class_type
114
+ hash
115
+ else
116
+ nil
152
117
  end
153
118
  end
154
119
 
@@ -164,22 +129,23 @@ module Wakame
164
129
  end
165
130
 
166
131
  def save(id, hash)
132
+ Wakame.log.debug("StatusDB.save(#{id}) called by #{Thread.current.to_s}") unless Thread.current == WorkerThread.worker_thread
167
133
  m = @model_class[id]
168
134
  if m.nil?
169
135
  m = @model_class.new
170
136
  m.id = id
171
137
  m.class_type = hash[AttributeHelper::CLASS_TYPE_KEY]
172
- end
138
+ end
173
139
  m.dump = hash.inspect
174
140
  m.save
175
141
  end
176
142
 
177
143
  def delete(id)
144
+ Wakame.log.debug("StatusDB.delete(#{id}) called by #{Thread.current.to_s}") unless Thread.current == WorkerThread.worker_thread
178
145
  @model_class[id].destroy
179
146
  end
180
147
 
181
148
  def clear_store
182
- setup_store
183
149
  end
184
150
 
185
151
  end
@@ -214,32 +180,34 @@ module Wakame
214
180
  obj = _instance_cache[id]
215
181
  return obj unless obj.nil?
216
182
 
217
- StatusDB.adapter.find(id) { |id, hash|
218
- if hash[AttributeHelper::CLASS_TYPE_KEY]
219
- klass_const = Util.build_const(hash[AttributeHelper::CLASS_TYPE_KEY])
220
- else
221
- klass_const = self.class
222
- end
223
-
224
- # klass_const class is equal to self class or child of self class
225
- if klass_const <= self
226
- obj = klass_const.new
227
- else
228
- raise "Can not instanciate the object #{klass_const.to_s} from #{self}"
229
- end
230
-
231
- obj.on_before_load
232
-
233
- obj.instance_variable_set(:@id, id)
234
- obj.instance_variable_set(:@_orig, hash.dup.freeze)
235
- obj.instance_variable_set(:@load_at, Time.now)
236
-
237
- hash.each { |k,v|
238
- obj.instance_variable_set("@#{k}", v)
239
- }
183
+ hash = StatusDB.barrier {
184
+ StatusDB.adapter.find(id)
185
+ }
186
+ return nil unless hash
240
187
 
241
- obj.on_after_load
188
+ if hash[AttributeHelper::CLASS_TYPE_KEY]
189
+ klass_const = Util.build_const(hash[AttributeHelper::CLASS_TYPE_KEY])
190
+ else
191
+ klass_const = self
192
+ end
193
+
194
+ # klass_const class is equal to self class or child of self class
195
+ if klass_const <= self
196
+ obj = klass_const.new
197
+ else
198
+ raise "Can not instanciate the object #{klass_const.to_s} from #{self}"
199
+ end
200
+
201
+ obj.on_before_load
202
+
203
+ obj.instance_variable_set(:@id, id)
204
+ obj.instance_variable_set(:@load_at, Time.now)
205
+
206
+ hash.each { |k,v|
207
+ obj.instance_variable_set("@#{k}", v)
242
208
  }
209
+
210
+ obj.on_after_load
243
211
 
244
212
  _instance_cache[id] = obj
245
213
  obj
@@ -247,13 +215,17 @@ module Wakame
247
215
 
248
216
 
249
217
  def find_all
250
- StatusDB.adapter.find_all(self.to_s).map { |id|
251
- find(id)
218
+ StatusDB.barrier {
219
+ StatusDB.adapter.find_all(self.to_s).map { |id|
220
+ find(id)
221
+ }
252
222
  }
253
223
  end
254
224
 
255
225
  def exists?(id)
256
- _instance_cache.has_key?(id) || StatusDB.adapter.exists?(id)
226
+ StatusDB.barrier {
227
+ _instance_cache.has_key?(id) || StatusDB.adapter.exists?(id)
228
+ }
257
229
  end
258
230
 
259
231
  # A helper method to define an accessor with persistent flag.
@@ -271,8 +243,9 @@ module Wakame
271
243
  obj = find(id)
272
244
  if obj
273
245
  obj.on_before_delete
274
-
275
- StatusDB.adapter.delete(id)
246
+ StatusDB.barrier {
247
+ StatusDB.adapter.delete(id)
248
+ }
276
249
  _instance_cache.delete(id)
277
250
 
278
251
  obj.on_after_delete
@@ -300,33 +273,18 @@ module Wakame
300
273
  @load_at.nil?
301
274
  end
302
275
 
303
- def dirty?(key=nil)
304
- return true if new_record?
305
-
306
- if key
307
- attr_attr = self.class.get_attr_attribute(key.to_sym)
308
- raise "#{key} is not the key to be saved" if attr_attr.nil? || !attr_attr[:persistent]
309
- return @_orig[key.to_sym] != self.__send__(key.to_sym)
310
- else
311
- self.class.merged_attr_attributes.each { |k,v|
312
- next unless v[:persistent]
313
- #p "@_orig[#{k.to_sym}]=#{@_orig[k.to_sym].inspect}"
314
- #p "@self.__send__(#{k.to_sym})=#{self.__send__(k.to_sym).inspect}"
315
- return true if @_orig[k.to_sym] != self.__send__(k.to_sym)
316
- }
317
- return false
318
- end
276
+ def dirty?
277
+ raise NotImplementedError
319
278
  end
320
279
 
321
280
  def save
322
- # return unless dirty?
323
- # raise "No change" unless dirty?
281
+ #return unless dirty?
324
282
 
325
283
  validate_on_save
326
284
 
327
285
  self.class.merged_attr_attributes.each { |k,v|
328
286
  next unless v[:persistent]
329
- if dirty?(k) && v[:call_after_changed]
287
+ if v[:call_after_changed]
330
288
  case v[:call_after_changed]
331
289
  when Symbol
332
290
  self.__send__(v[:call_after_changed].to_sym) # if self.respond_to?(v[:call_after_changed].to_sym)
@@ -341,9 +299,9 @@ module Wakame
341
299
  dumper.call(k)
342
300
  end
343
301
  }
344
- @_orig = hash_saved.dup.freeze
345
-
346
- StatusDB.adapter.save(self.id, hash_saved)
302
+ StatusDB.barrier {
303
+ StatusDB.adapter.save(self.id, hash_saved)
304
+ }
347
305
  end
348
306
 
349
307
  def delete
@@ -352,7 +310,29 @@ module Wakame
352
310
 
353
311
  def reload
354
312
  self.class._instance_cache.delete(self.id)
355
- self.class.find(self.id)
313
+ hash = StatusDB.barrier {
314
+ StatusDB.adapter.find(self.id)
315
+ }
316
+ if hash[AttributeHelper::CLASS_TYPE_KEY]
317
+ klass_const = Util.build_const(hash[AttributeHelper::CLASS_TYPE_KEY])
318
+ else
319
+ klass_const = self.class
320
+ end
321
+
322
+ # klass_const class is equal to self class or child of self class
323
+ unless klass_const <= self.class
324
+ raise "The class \"#{klass_const.to_s}\" has no relationship to #{self.class}"
325
+ end
326
+
327
+ on_before_load
328
+
329
+ @load_at = Time.now
330
+
331
+ hash.each { |k,v|
332
+ instance_variable_set("@#{k}", v)
333
+ }
334
+
335
+ on_after_load
356
336
  end
357
337
 
358
338
  # Callback methods
@@ -209,9 +209,12 @@ module AttributeHelper
209
209
 
210
210
  def merged_attr_attributes
211
211
  hash = {}
212
+
213
+ deep_merge = proc {|key,v1,v2| Hash === v1 && Hash === v2 ? v1.merge(v2, &deep_merge) : v2}
214
+
212
215
  self.ancestors.reverse.each { |klass|
213
216
  next unless klass.include?(AttributeHelper)
214
- hash.merge!(klass.attr_attributes.dup)
217
+ hash.merge!(klass.attr_attributes, &deep_merge)
215
218
  }
216
219
  hash
217
220
  end
@@ -220,6 +223,16 @@ module AttributeHelper
220
223
  merged_attr_attributes[attr_name]
221
224
  end
222
225
 
226
+ # Update attr_attributes[name][:default] value.
227
+ # This works for existing name key.
228
+ def update_attribute(name, v)
229
+ attr_attr = get_attr_attribute(name.to_sym)
230
+ raise "No such defined attribute: #{name}" if attr_attr.nil?
231
+ attr_attributes[name.to_sym] ||= {}
232
+ attr_attributes[name.to_sym].merge!({:default=>v})
233
+ name
234
+ end
235
+
223
236
  def def_attribute(name, *args)
224
237
  attr = begin
225
238
  if args.size == 0
@@ -233,9 +246,10 @@ module AttributeHelper
233
246
  end
234
247
  end
235
248
  end
236
-
237
249
  (attr_attributes[name.to_sym] ||= {}).merge!(attr)
238
250
 
251
+ attr = self.merged_attr_attributes
252
+
239
253
  if attr[:read_only]
240
254
  if self.respond_to? "#{name}=".to_sym
241
255
  class_eval %Q{
@@ -245,7 +259,6 @@ module AttributeHelper
245
259
  else
246
260
  class_eval <<-__E__
247
261
  def #{name}=(v)
248
- self.#{name}
249
262
  @#{name}=v
250
263
  end
251
264
 
@@ -256,18 +269,16 @@ module AttributeHelper
256
269
  class_eval <<-__E__
257
270
  def #{name}
258
271
  if @#{name}.nil?
259
- retrieve_attr_attribute { |a|
260
- if a.has_key?(:#{name})
261
- defval = a[:#{name}][:default]
262
- case defval
263
- when Proc
264
- @#{name} = defval.call(self)
265
- else
266
- @#{name} = defval.dup rescue defval
267
- end
268
- break
269
- end
270
- }
272
+ a = self.class.get_attr_attribute(:#{name})
273
+ if a
274
+ defval = a[:default]
275
+ @#{name} = case defval
276
+ when Proc
277
+ defval.call(self)
278
+ else
279
+ defval.dup rescue defval
280
+ end
281
+ end
271
282
  end
272
283
  @#{name}
273
284
  end
@@ -11,6 +11,7 @@ require 'test/unit'
11
11
 
12
12
  require 'wakame'
13
13
  require 'wakame/initializer'
14
+ require 'wakame/util'
14
15
 
15
16
  require 'ext/eventmachine'
16
17
 
@@ -6,10 +6,8 @@ $:.unshift(File.dirname(__FILE__))
6
6
  require 'setup_master.rb'
7
7
 
8
8
  require 'wakame'
9
- #require 'wakame/master'
10
9
  require 'wakame/service'
11
10
  require 'wakame/queue_declare'
12
- #require 'wakame/packets'
13
11
 
14
12
  class TestMaster < Test::Unit::TestCase
15
13
 
@@ -0,0 +1,21 @@
1
+
2
+ $:.unshift(File.dirname(__FILE__) + '/../lib')
3
+ $:.unshift(File.dirname(__FILE__))
4
+
5
+ require 'setup_master.rb'
6
+
7
+ require 'test/unit'
8
+
9
+ Wakame.config.status_db_dsn = 'sqlite:/'
10
+ Wakame::Initializer.run(:setup_database)
11
+
12
+ require 'wakame/models/agent_pool'
13
+
14
+ class TestModelAgentPool < Test::Unit::TestCase
15
+ include Wakame::Models
16
+
17
+ def test_pool
18
+ AgentPool.instance
19
+ AgentPool.instance.reset
20
+ end
21
+ end