wakame 0.4.0

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.
Files changed (147) hide show
  1. data/History.txt +20 -0
  2. data/README.rdoc +63 -0
  3. data/Rakefile +86 -0
  4. data/VERSION +1 -0
  5. data/app_generators/wakame/templates/README +0 -0
  6. data/app_generators/wakame/templates/Rakefile +18 -0
  7. data/app_generators/wakame/templates/bin/wakame-agent +9 -0
  8. data/app_generators/wakame/templates/bin/wakame-master +9 -0
  9. data/app_generators/wakame/templates/bin/wakameadm +9 -0
  10. data/app_generators/wakame/templates/cluster/resources/apache_app/apache_app.rb +54 -0
  11. data/app_generators/wakame/templates/cluster/resources/apache_app/conf/apache2.conf +46 -0
  12. data/app_generators/wakame/templates/cluster/resources/apache_app/conf/envvars-app +7 -0
  13. data/app_generators/wakame/templates/cluster/resources/apache_app/conf/sites-app.conf +23 -0
  14. data/app_generators/wakame/templates/cluster/resources/apache_app/conf/system-app.conf +67 -0
  15. data/app_generators/wakame/templates/cluster/resources/apache_app/init.d/apache2-app +192 -0
  16. data/app_generators/wakame/templates/cluster/resources/apache_lb/apache_lb.rb +56 -0
  17. data/app_generators/wakame/templates/cluster/resources/apache_lb/conf/apache2.conf +46 -0
  18. data/app_generators/wakame/templates/cluster/resources/apache_lb/conf/envvars-lb +6 -0
  19. data/app_generators/wakame/templates/cluster/resources/apache_lb/conf/sites-lb.conf +54 -0
  20. data/app_generators/wakame/templates/cluster/resources/apache_lb/conf/system-lb.conf +75 -0
  21. data/app_generators/wakame/templates/cluster/resources/apache_lb/init.d/apache2-lb +192 -0
  22. data/app_generators/wakame/templates/cluster/resources/apache_www/apache_www.rb +50 -0
  23. data/app_generators/wakame/templates/cluster/resources/apache_www/conf/apache2.conf +47 -0
  24. data/app_generators/wakame/templates/cluster/resources/apache_www/conf/envvars-www +7 -0
  25. data/app_generators/wakame/templates/cluster/resources/apache_www/conf/sites-www.conf +23 -0
  26. data/app_generators/wakame/templates/cluster/resources/apache_www/conf/system-www.conf +63 -0
  27. data/app_generators/wakame/templates/cluster/resources/apache_www/init.d/apache2-www +192 -0
  28. data/app_generators/wakame/templates/cluster/resources/ec2_elastic_ip/ec2_elastic_ip.rb +39 -0
  29. data/app_generators/wakame/templates/cluster/resources/mysql_master/conf/my.cnf +154 -0
  30. data/app_generators/wakame/templates/cluster/resources/mysql_master/init.d/mysql +185 -0
  31. data/app_generators/wakame/templates/cluster/resources/mysql_master/mysql_master.rb +174 -0
  32. data/app_generators/wakame/templates/config/boot.rb +85 -0
  33. data/app_generators/wakame/templates/config/cluster.rb +64 -0
  34. data/app_generators/wakame/templates/config/environments/common.rb +0 -0
  35. data/app_generators/wakame/templates/config/environments/ec2.rb +3 -0
  36. data/app_generators/wakame/templates/config/environments/stand_alone.rb +0 -0
  37. data/app_generators/wakame/templates/config/init.d/wakame-agent +72 -0
  38. data/app_generators/wakame/templates/config/init.d/wakame-master +73 -0
  39. data/app_generators/wakame/wakame_generator.rb +124 -0
  40. data/bin/wakame +18 -0
  41. data/contrib/imagesetup.sh +77 -0
  42. data/lib/ext/eventmachine.rb +86 -0
  43. data/lib/ext/shellwords.rb +172 -0
  44. data/lib/ext/uri.rb +15 -0
  45. data/lib/wakame/action.rb +156 -0
  46. data/lib/wakame/actions/destroy_instances.rb +39 -0
  47. data/lib/wakame/actions/launch_cluster.rb +31 -0
  48. data/lib/wakame/actions/migrate_service.rb +65 -0
  49. data/lib/wakame/actions/propagate_instances.rb +95 -0
  50. data/lib/wakame/actions/reload_service.rb +21 -0
  51. data/lib/wakame/actions/scaleout_when_high_load.rb +44 -0
  52. data/lib/wakame/actions/shutdown_cluster.rb +22 -0
  53. data/lib/wakame/actions/shutdown_vm.rb +19 -0
  54. data/lib/wakame/actions/start_service.rb +64 -0
  55. data/lib/wakame/actions/stop_service.rb +49 -0
  56. data/lib/wakame/actions/util.rb +71 -0
  57. data/lib/wakame/actor/daemon.rb +37 -0
  58. data/lib/wakame/actor/service_monitor.rb +21 -0
  59. data/lib/wakame/actor/system.rb +46 -0
  60. data/lib/wakame/actor.rb +33 -0
  61. data/lib/wakame/agent.rb +226 -0
  62. data/lib/wakame/amqp_client.rb +219 -0
  63. data/lib/wakame/command/action_status.rb +62 -0
  64. data/lib/wakame/command/actor.rb +23 -0
  65. data/lib/wakame/command/clone_service.rb +12 -0
  66. data/lib/wakame/command/launch_cluster.rb +15 -0
  67. data/lib/wakame/command/migrate_service.rb +21 -0
  68. data/lib/wakame/command/propagate_service.rb +24 -0
  69. data/lib/wakame/command/shutdown_cluster.rb +15 -0
  70. data/lib/wakame/command/status.rb +81 -0
  71. data/lib/wakame/command.rb +31 -0
  72. data/lib/wakame/command_queue.rb +44 -0
  73. data/lib/wakame/configuration.rb +93 -0
  74. data/lib/wakame/daemonize.rb +96 -0
  75. data/lib/wakame/event.rb +232 -0
  76. data/lib/wakame/event_dispatcher.rb +154 -0
  77. data/lib/wakame/graph.rb +79 -0
  78. data/lib/wakame/initializer.rb +162 -0
  79. data/lib/wakame/instance_counter.rb +78 -0
  80. data/lib/wakame/logger.rb +12 -0
  81. data/lib/wakame/manager/commands.rb +134 -0
  82. data/lib/wakame/master.rb +369 -0
  83. data/lib/wakame/monitor/agent.rb +50 -0
  84. data/lib/wakame/monitor/service.rb +183 -0
  85. data/lib/wakame/monitor.rb +69 -0
  86. data/lib/wakame/packets.rb +160 -0
  87. data/lib/wakame/queue_declare.rb +14 -0
  88. data/lib/wakame/rule.rb +116 -0
  89. data/lib/wakame/rule_engine.rb +202 -0
  90. data/lib/wakame/runner/administrator_command.rb +112 -0
  91. data/lib/wakame/runner/agent.rb +81 -0
  92. data/lib/wakame/runner/master.rb +93 -0
  93. data/lib/wakame/scheduler.rb +251 -0
  94. data/lib/wakame/service.rb +914 -0
  95. data/lib/wakame/template.rb +189 -0
  96. data/lib/wakame/trigger.rb +66 -0
  97. data/lib/wakame/triggers/instance_count_update.rb +45 -0
  98. data/lib/wakame/triggers/load_history.rb +107 -0
  99. data/lib/wakame/triggers/maintain_ssh_known_hosts.rb +43 -0
  100. data/lib/wakame/triggers/process_command.rb +34 -0
  101. data/lib/wakame/triggers/shutdown_unused_vm.rb +16 -0
  102. data/lib/wakame/util.rb +569 -0
  103. data/lib/wakame/vm_manipulator.rb +186 -0
  104. data/lib/wakame.rb +59 -0
  105. data/tasks/ec2.rake +127 -0
  106. data/tests/cluster.json +3 -0
  107. data/tests/conf/a +1 -0
  108. data/tests/conf/b +1 -0
  109. data/tests/conf/c +1 -0
  110. data/tests/setup_agent.rb +39 -0
  111. data/tests/setup_master.rb +28 -0
  112. data/tests/test_actor.rb +54 -0
  113. data/tests/test_agent.rb +218 -0
  114. data/tests/test_amqp_client.rb +94 -0
  115. data/tests/test_graph.rb +36 -0
  116. data/tests/test_master.rb +167 -0
  117. data/tests/test_monitor.rb +47 -0
  118. data/tests/test_rule_engine.rb +127 -0
  119. data/tests/test_scheduler.rb +123 -0
  120. data/tests/test_service.rb +60 -0
  121. data/tests/test_template.rb +67 -0
  122. data/tests/test_uri_amqp.rb +19 -0
  123. data/tests/test_util.rb +71 -0
  124. data/wakame_generators/resource/resource_generator.rb +54 -0
  125. data/wakame_generators/resource/templates/apache_app/apache_app.rb +60 -0
  126. data/wakame_generators/resource/templates/apache_app/conf/apache2.conf +46 -0
  127. data/wakame_generators/resource/templates/apache_app/conf/envvars-app +7 -0
  128. data/wakame_generators/resource/templates/apache_app/conf/sites-app.conf +23 -0
  129. data/wakame_generators/resource/templates/apache_app/conf/system-app.conf +67 -0
  130. data/wakame_generators/resource/templates/apache_app/init.d/apache2-app +192 -0
  131. data/wakame_generators/resource/templates/apache_lb/apache_lb.rb +67 -0
  132. data/wakame_generators/resource/templates/apache_lb/conf/apache2.conf +46 -0
  133. data/wakame_generators/resource/templates/apache_lb/conf/envvars-lb +6 -0
  134. data/wakame_generators/resource/templates/apache_lb/conf/sites-lb.conf +54 -0
  135. data/wakame_generators/resource/templates/apache_lb/conf/system-lb.conf +75 -0
  136. data/wakame_generators/resource/templates/apache_lb/init.d/apache2-lb +192 -0
  137. data/wakame_generators/resource/templates/apache_www/apache_www.rb +56 -0
  138. data/wakame_generators/resource/templates/apache_www/conf/apache2.conf +47 -0
  139. data/wakame_generators/resource/templates/apache_www/conf/envvars-www +7 -0
  140. data/wakame_generators/resource/templates/apache_www/conf/sites-www.conf +23 -0
  141. data/wakame_generators/resource/templates/apache_www/conf/system-www.conf +63 -0
  142. data/wakame_generators/resource/templates/apache_www/init.d/apache2-www +192 -0
  143. data/wakame_generators/resource/templates/ec2_elastic_ip/ec2_elastic_ip.rb +39 -0
  144. data/wakame_generators/resource/templates/mysql_master/conf/my.cnf +154 -0
  145. data/wakame_generators/resource/templates/mysql_master/init.d/mysql +185 -0
  146. data/wakame_generators/resource/templates/mysql_master/mysql_master.rb +119 -0
  147. metadata +289 -0
@@ -0,0 +1,569 @@
1
+
2
+
3
+ require 'digest/sha1'
4
+ require 'hmac-sha1'
5
+ require 'open4'
6
+
7
+ module Wakame
8
+ module Util
9
+
10
+ def ssh_known_hosts_hash(hostname, key=nil)
11
+ # Generate 20bytes random value
12
+ key = Array.new(20).collect{rand(0xFF).to_i}.pack('c*') if key.nil?
13
+
14
+ "|1|#{[key].pack('m').chop}|#{[HMAC::SHA1.digest(key, hostname)].pack('m').chop}"
15
+ end
16
+ module_function :ssh_known_hosts_hash
17
+
18
+
19
+ def gen_id(str=nil)
20
+ Digest::SHA1.hexdigest( (str.nil? ? rand.to_s : str) )
21
+ end
22
+ module_function :gen_id
23
+
24
+
25
+ def build_const(name)
26
+ name.to_s.split(/::/).inject(Object) {|c,name| c.const_get(name) }
27
+ end
28
+ module_function :build_const
29
+
30
+
31
+ def new_(class_or_str, *args)
32
+ if class_or_str.is_a? Class
33
+ class_or_str.new(*args)
34
+ else
35
+ c = build_const(class_or_str.to_s)
36
+ c.new(*args)
37
+ end
38
+ end
39
+ module_function :new_
40
+
41
+
42
+ # Copied from http://github.com/ezmobius/nanite/
43
+ ##
44
+ # Convert to snake case.
45
+ #
46
+ # "FooBar".snake_case #=> "foo_bar"
47
+ # "HeadlineCNNNews".snake_case #=> "headline_cnn_news"
48
+ # "CNN".snake_case #=> "cnn"
49
+ #
50
+ # @return [String] Receiver converted to snake case.
51
+ #
52
+ # @api public
53
+ def snake_case(const)
54
+ const = const.to_s
55
+ return const.downcase if const =~ /^[A-Z\d]+$/
56
+ const.gsub(/\B([A-Z\d]+)|([A-Z]+)(?=[A-Z][a-z]?)/, '_\&') =~ /_*(.*)/
57
+ return $+.downcase.gsub(/[_]+/, '_')
58
+ end
59
+ module_function :snake_case
60
+
61
+ # Copied from http://github.com/ezmobius/nanite/
62
+ ##
63
+ # Convert a constant name to a path, assuming a conventional structure.
64
+ #
65
+ # "FooBar::Baz".to_const_path # => "foo_bar/baz"
66
+ #
67
+ # @return [String] Path to the file containing the constant named by receiver
68
+ # (constantized string), assuming a conventional structure.
69
+ #
70
+ # @api public
71
+ def to_const_path(const)
72
+ snake_case(const).gsub(/::/, "/")
73
+ end
74
+ module_function :to_const_path
75
+
76
+
77
+ def exec(command, &capture)
78
+ outputs = []
79
+ Wakame.log.debug("#{self}.exec(#{command})")
80
+ cmdstat = ::Open4.popen4(command) { |pid, stdin, stdout, stderr|
81
+ stdout.each { |l|
82
+ capture.call(l, :stdout) if capture
83
+ outputs << l
84
+ }
85
+ stderr.each { |l|
86
+ capture.call(l, :stderr) if capture
87
+ outputs << l
88
+ }
89
+ }
90
+ Wakame.log.debug(outputs.join(''))
91
+ raise "Command Failed (exit=#{cmdstat.exitstatus}): #{command}" unless cmdstat.exitstatus == 0
92
+ end
93
+ module_function :exec
94
+
95
+ def spawn(command, &capture)
96
+ outputs = []
97
+ Wakame.log.debug("#{self}.spawn(#{command})")
98
+ cmdstat = ::Open4.popen4(command) { |pid, stdin, stdout, stderr|
99
+ stdout.each { |l|
100
+ capture.call(l, :stdout) if capture
101
+ outputs << l
102
+ }
103
+ stderr.each { |l|
104
+ capture.call(l, :stderr) if capture
105
+ outputs << l
106
+ }
107
+ }
108
+ Wakame.log.debug(outputs.join(''))
109
+ cmdstat
110
+ end
111
+ module_function :spawn
112
+
113
+ end
114
+ end
115
+
116
+
117
+ module ThreadImmutable
118
+ class IllegalCrossThreadMethodCall < StandardError; end
119
+
120
+
121
+ module ClassMethods
122
+ def thread_immutable_methods(*args)
123
+ return if args.empty?
124
+
125
+ args.each { |n|
126
+ # Proc can not be passed a block due to 1.8's limitation. The following will work in 1.9.
127
+ #um = instance_method(n) || next
128
+ #define_method(n) { |*args, &blk|
129
+ # thread_check
130
+ # um.bind(self).call(*args, &blk)
131
+ #}
132
+
133
+ if method_defined?(n)
134
+ alias_method "#{n}_no_thread_check", n.to_sym
135
+
136
+ eval <<-__E__
137
+ def #{n}(*args, &blk)
138
+ thread_check
139
+ #{n}_no_thread_check(*args, &blk)
140
+ end
141
+ __E__
142
+ end
143
+ }
144
+ end
145
+ end
146
+
147
+ def self.included(klass)
148
+ klass.extend ClassMethods
149
+ end
150
+
151
+ # def self.included(klass)
152
+ # klass.class_eval {
153
+ # _um_constructor = self.instance_method(:initialize)
154
+ # if _um_constructor
155
+ # define_method(:initialize) { |*args|
156
+ # bind_thread
157
+ # _um_constructor.bind(self).call(*args)
158
+ # }
159
+ # end
160
+ # }
161
+ # end
162
+
163
+ # def self.method_added2(name)
164
+ # if name == :initialize
165
+ #
166
+ # _um_constructor = instance_method(:initialize)
167
+ # define_method(:initialize) { |*args|
168
+ # bind_thread
169
+ # _um_constructor.bind(self).call(*args)
170
+ # }
171
+ # end
172
+ # end
173
+
174
+
175
+ def bind_thread(thread=Thread.current)
176
+ @target_thread = thread
177
+ #puts "bound thread: #{@target_thread.inspect} to #{self.class} object"
178
+ end
179
+
180
+ def thread_check
181
+ #puts "@target_thread == Thread.main : #{@target_thread == Thread.main}"
182
+ raise "Thread is not bound." if @target_thread.nil?
183
+ raise IllegalCrossThreadMethodCall unless target_thread?
184
+ end
185
+
186
+ def target_thread?(t=Thread.current)
187
+ @target_thread == t
188
+ end
189
+
190
+
191
+ def target_thread
192
+ @target_thread
193
+ end
194
+
195
+ end
196
+
197
+
198
+
199
+ module AttributeHelper
200
+
201
+ PRIMITIVE_CLASSES=[NilClass, TrueClass, FalseClass, Numeric, String, Symbol]
202
+ CONVERT_CLASSES={Time => proc{|i| i.to_s } }
203
+
204
+ module ClassMethods
205
+ def attr_attributes
206
+ @attr_attributes ||= {}
207
+ end
208
+
209
+ def attr(name, assignable=false)
210
+ attr_attributes[name.to_sym]={}
211
+ attr_without_trap(name, assignable)
212
+ end
213
+
214
+ # Override Object.attr_accessor to
215
+ def attr_accessor(*args)
216
+ args.each { |name|
217
+ attr(name, true)
218
+ }
219
+ end
220
+
221
+ def attr_reader(*args)
222
+ args.each { |name|
223
+ attr(name, false)
224
+ }
225
+ end
226
+
227
+ def attr_writer(*args)
228
+ args.each { |name|
229
+ attr(name, true)
230
+ }
231
+ end
232
+
233
+ def def_attribute(name, *args)
234
+ attr = {}
235
+ attr_attributes[name.to_sym] = begin
236
+ if args.size == 0
237
+ {:default=>nil}
238
+ else
239
+ case args[0]
240
+ when Hash
241
+ args[0].dup
242
+ else
243
+ {:default=>args[0]}
244
+ end
245
+ end
246
+ end
247
+ class_eval <<-__E__
248
+ def #{name}=(v)
249
+ @#{name}=v
250
+ end
251
+
252
+ def #{name}
253
+ if @#{name}.nil?
254
+ retrieve_attr_attribute { |a|
255
+ if a.has_key?(:#{name})
256
+ defval = a[:#{name}][:default]
257
+ case defval
258
+ when Proc
259
+ @#{name} = defval.call(self)
260
+ else
261
+ @#{name} = defval
262
+ end
263
+ break
264
+ end
265
+ }
266
+ end
267
+ @#{name}
268
+ end
269
+
270
+ public :#{name}, :#{name}=
271
+ __E__
272
+ end
273
+
274
+ end
275
+
276
+ private
277
+ def self.included(klass)
278
+ klass.class.class_eval {
279
+ alias :attr_without_trap :attr unless self.respond_to?(:attr_without_trap, true)
280
+ }
281
+ klass.extend ClassMethods
282
+ end
283
+
284
+
285
+ public
286
+ def dump_attrs(root=nil)
287
+ if root.nil?
288
+ root = self
289
+ end
290
+
291
+ return dump_internal(root)
292
+ end
293
+ #thread_immutable_method :dump_attrs if self.kind_of?(ThreadImmutable)
294
+ #module_function :dump_attrs
295
+
296
+
297
+ private
298
+ def retrieve_attr_attribute(&blk)
299
+ self.class.ancestors.each { |klass|
300
+ blk.call(klass.attr_attributes) if klass.include?(AttributeHelper)
301
+ }
302
+ end
303
+
304
+ def dump_internal(root)
305
+ case root
306
+ when AttributeHelper
307
+ t={}
308
+ t[:type] = root.class.to_s
309
+
310
+ retrieve_attr_attribute { |a|
311
+ a.each_key {|k| t[k] = dump_internal(root.__send__(k.to_sym)) }
312
+ }
313
+ t
314
+ when Array
315
+ root.collect { |a| dump_internal(a) }
316
+ when Hash
317
+ t={}
318
+ root.each {|k,v| t[k] = dump_internal(v) }
319
+ t
320
+ else
321
+ if CONVERT_CLASSES.any?{|t, p| root.kind_of?(t) }
322
+ CONVERT_CLASSES[root.class].call(root)
323
+ elsif PRIMITIVE_CLASSES.any?{|p| root.kind_of?(p) }
324
+ root
325
+ #elsif root.respond_to?(:dump_attrs)
326
+ #dump_internal(root.dump_attrs)
327
+ else
328
+ raise TypeError, "#{root.class} does not support to dump attributes"
329
+ end
330
+ end
331
+ end
332
+
333
+ end
334
+
335
+
336
+ class SortedHash < Hash
337
+ def initialize
338
+ @keyorder=[]
339
+ end
340
+
341
+
342
+ def store(key, value)
343
+ raise TypeError, "#{key} is not Comparable" unless key.kind_of?(Comparable)
344
+ if has_key?(key)
345
+ ret = super(key, value)
346
+ else
347
+ ret = super(key, value)
348
+ @keyorder << key
349
+ @keyorder.sort!
350
+
351
+ end
352
+ ret
353
+ end
354
+
355
+ def []=(key, value)
356
+ store(key, value)
357
+ end
358
+
359
+ def delete(key, &blk)
360
+ if has_key?(key)
361
+ @keyorder.delete(key)
362
+ super(key, &blk)
363
+ end
364
+ end
365
+
366
+ def keys
367
+ @keyorder
368
+ end
369
+
370
+ def each(&blk)
371
+ @keyorder.each { |k|
372
+ blk.call(k, self[k])
373
+ }
374
+ end
375
+
376
+ def first_key
377
+ @keyorder.first
378
+ end
379
+
380
+ def first
381
+ self[first_key]
382
+ end
383
+
384
+ def last_key
385
+ @keyorder.last
386
+ end
387
+
388
+ def last
389
+ self[last_key]
390
+ end
391
+
392
+ def clear
393
+ super
394
+ @keyorder.clear
395
+ end
396
+
397
+ def inspect
398
+ str = "{"
399
+ str << @keyorder.collect{|k| "#{k}=>#{self[k]}" }.join(', ')
400
+ str << "}"
401
+ str
402
+ end
403
+
404
+ def invert
405
+ raise NotImplementedError
406
+ end
407
+
408
+ end
409
+
410
+
411
+ module FilterChain
412
+ def self.included(klass)
413
+ klass.class_eval {
414
+ def self.filter_chain
415
+ @filter_chain ||= []
416
+ end
417
+
418
+ def self.append_filter(&blk)
419
+ self.filter_chain << blk
420
+ end
421
+ }
422
+ end
423
+
424
+ def run_filter(pass_obj=nil)
425
+ retrieve_filter_chain { |filter_chain|
426
+ filter_chain.each { |filter_proc|
427
+ begin
428
+ ret = filter_proc.call(pass_obj)
429
+ rescue => e
430
+ ret = false
431
+ end
432
+
433
+ unless ret
434
+ raise
435
+ end
436
+ }
437
+ }
438
+ end
439
+
440
+ private
441
+ def retrieve_filter_chain(&blk)
442
+ order = []
443
+ self.class.ancestors.each { |klass|
444
+ order << klass if klass.include?(FilterChain)
445
+ }
446
+
447
+ order.reverse.each { |klass|
448
+ blk.call(klass.filter_chain)
449
+ }
450
+ end
451
+
452
+ end
453
+
454
+
455
+ class ConditionalWait
456
+ class TimeoutError < StandardError; end
457
+ include ThreadImmutable
458
+
459
+ def initialize(&blk)
460
+ bind_thread
461
+ @wait_queue = ::Queue.new
462
+ @wait_tickets = []
463
+ @poll_threads = []
464
+ @event_tickets = []
465
+
466
+ blk.call(self) if blk
467
+ end
468
+
469
+ def poll( period=5, max_retry=10, &blk)
470
+ wticket = Wakame::Util.gen_id
471
+ @poll_threads << Thread.new {
472
+ retry_count = 0
473
+
474
+ begin
475
+ catch(:finish) {
476
+ while retry_count < max_retry
477
+ start_at = Time.now
478
+ if blk.call == true
479
+ throw :finish
480
+ end
481
+ Thread.pass
482
+ if period > 0
483
+ t = Time.now - start_at
484
+ sleep (period - t) if period > t
485
+ end
486
+ retry_count += 1
487
+ end
488
+ }
489
+
490
+ if retry_count >= max_retry
491
+ Wakame.log.error('Over retry count')
492
+ raise 'Over retry count'
493
+ end
494
+
495
+ rescue => e
496
+ Wakame.log.error(e)
497
+ @wait_queue << [false, wticket, e]
498
+ else
499
+ @wait_queue << [true, wticket]
500
+ end
501
+ }
502
+ @poll_threads.last[:name]="#{self.class} poll"
503
+
504
+ @wait_tickets << wticket
505
+ end
506
+ thread_immutable_methods :poll
507
+
508
+ def wait_event(event_class, &blk)
509
+ wticket = Wakame::Util.gen_id
510
+ Wakame.log.debug("#{self.class} called wait_event(#{event_class}) on thread #{Thread.current} (target_thread=#{self.target_thread?}). has_blk=#{blk}")
511
+ ticket = Wakame::EventDispatcher.subscribe(event_class) { |event|
512
+ begin
513
+ if blk.call(event) == true
514
+ Wakame::EventDispatcher.unsubscribe(ticket)
515
+ @wait_queue << [true, wticket]
516
+ end
517
+ rescue => e
518
+ Wakame.log.error(e)
519
+ Wakame::EventDispatcher.unsubscribe(ticket)
520
+ @wait_queue << [false, wticket, e]
521
+ end
522
+ }
523
+ @event_tickets << ticket
524
+
525
+ @wait_tickets << wticket
526
+ end
527
+ thread_immutable_methods :wait_event
528
+
529
+ def wait(tout=nil)
530
+
531
+ unless @wait_tickets.empty?
532
+ Wakame.log.debug("#{self.class} waits for #{@wait_tickets.size} num of event(s)/polling(s).")
533
+
534
+ timeout(tout, TimeoutError) {
535
+ while @wait_tickets.size > 0 && q = @wait_queue.shift
536
+ @wait_tickets.delete(q[1])
537
+
538
+ unless q[0]
539
+ Wakame.log.debug("#{q[1]} failed with #{q[2]}")
540
+ raise q[2]
541
+ end
542
+ end
543
+ }
544
+ end
545
+
546
+ ensure
547
+ # Cleanup generated threads/event tickets
548
+ @poll_threads.each { |t|
549
+ begin
550
+ t.kill
551
+ rescue => e
552
+ Wakame.log.error(e)
553
+ end
554
+ }
555
+ @event_tickets.each { |t| Wakame::EventDispatcher.unsubscribe(t) }
556
+ end
557
+ thread_immutable_methods :wait
558
+
559
+ def self.wait(timeout=60*30, &blk)
560
+ cond = ConditionalWait.new
561
+ cond.bind_thread(Thread.current)
562
+
563
+ #cond.instance_eval(&blk)
564
+ blk.call(cond)
565
+
566
+ cond.wait(timeout)
567
+ end
568
+
569
+ end