wakame 0.4.0

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