sensu 0.9.9.beta.2 → 0.9.9.beta.3

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/CHANGELOG.md CHANGED
@@ -15,6 +15,8 @@ TCP handler socket timeout, which defaults to 10 seconds.
15
15
 
16
16
  Check execution timeout.
17
17
 
18
+ Server extensions (mutators & handlers).
19
+
18
20
  ### Other
19
21
 
20
22
  Server is now using basic AMQP QoS (prefetch), just enough back pressure.
data/lib/sensu/api.rb CHANGED
@@ -21,9 +21,10 @@ module Sensu
21
21
  end
22
22
 
23
23
  def bootstrap(options={})
24
- $logger = Sensu::Logger.get
25
- base = Sensu::Base.new(options)
24
+ base = Base.new(options)
25
+ $logger = base.logger
26
26
  $settings = base.settings
27
+ base.setup_process
27
28
  if $settings[:api][:user] && $settings[:api][:password]
28
29
  use Rack::Auth::Basic do |user, password|
29
30
  user == $settings[:api][:user] && password == $settings[:api][:password]
@@ -35,20 +36,18 @@ module Sensu
35
36
  $logger.debug('connecting to redis', {
36
37
  :settings => $settings[:redis]
37
38
  })
38
- connection_failure = Proc.new do
39
- $logger.fatal('cannot connect to redis', {
40
- :settings => $settings[:redis]
39
+ $redis = Redis.connect($settings[:redis])
40
+ $redis.on_error do |error|
41
+ $logger.fatal('redis connection error', {
42
+ :error => error.to_s
41
43
  })
42
- $logger.fatal('SENSU NOT RUNNING!')
43
- if $rabbitmq
44
- $rabbitmq.close
45
- end
46
- exit 2
44
+ stop
47
45
  end
48
- $redis = Sensu::Redis.connect($settings[:redis], :on_tcp_connection_failure => connection_failure)
49
- $redis.on_tcp_connection_loss do |connection, settings|
46
+ $redis.before_reconnect do
50
47
  $logger.warn('reconnecting to redis')
51
- connection.reconnect(false, 10)
48
+ end
49
+ $redis.after_reconnect do
50
+ $logger.info('reconnected to redis')
52
51
  end
53
52
  end
54
53
 
@@ -56,30 +55,20 @@ module Sensu
56
55
  $logger.debug('connecting to rabbitmq', {
57
56
  :settings => $settings[:rabbitmq]
58
57
  })
59
- connection_failure = Proc.new do
60
- $logger.fatal('cannot connect to rabbitmq', {
61
- :settings => $settings[:rabbitmq]
58
+ $rabbitmq = RabbitMQ.connect($settings[:rabbitmq])
59
+ $rabbitmq.on_error do |error|
60
+ $logger.fatal('rabbitmq connection error', {
61
+ :error => error.to_s
62
62
  })
63
- $logger.fatal('SENSU NOT RUNNING!')
64
- $redis.close
65
- exit 2
63
+ stop
66
64
  end
67
- $rabbitmq = AMQP.connect($settings[:rabbitmq], {
68
- :on_tcp_connection_failure => connection_failure,
69
- :on_possible_authentication_failure => connection_failure
70
- })
71
- $rabbitmq.logger = Sensu::NullLogger.get
72
- $rabbitmq.on_tcp_connection_loss do |connection, settings|
73
- unless connection.reconnecting?
74
- $logger.warn('reconnecting to rabbitmq')
75
- connection.periodically_reconnect(5)
76
- end
65
+ $rabbitmq.before_reconnect do
66
+ $logger.warn('reconnecting to rabbitmq')
77
67
  end
78
- $rabbitmq.on_skipped_heartbeats do
79
- $logger.warn('skipped rabbitmq heartbeat')
68
+ $rabbitmq.after_reconnect do
69
+ $logger.info('reconnected to rabbitmq')
80
70
  end
81
- $amq = AMQP::Channel.new($rabbitmq)
82
- $amq.auto_recovery = true
71
+ $amq = $rabbitmq.channel
83
72
  end
84
73
 
85
74
  def start
@@ -108,29 +97,9 @@ module Sensu
108
97
  end
109
98
  end
110
99
 
111
- def run_test(options={}, &block)
100
+ def test(options={})
112
101
  bootstrap(options)
113
102
  start
114
- $settings[:client][:timestamp] = Time.now.to_i
115
- $redis.set('client:' + $settings[:client][:name], $settings[:client].to_json).callback do
116
- $redis.sadd('clients', $settings[:client][:name]).callback do
117
- $redis.hset('events:' + $settings[:client][:name], 'test', {
118
- :output => 'CRITICAL',
119
- :status => 2,
120
- :issued => Time.now.to_i,
121
- :flapping => false,
122
- :occurrences => 1
123
- }.to_json).callback do
124
- $redis.set('stash:test/test', {:key => 'value'}.to_json).callback do
125
- $redis.sadd('stashes', 'test/test').callback do
126
- EM::Timer.new(0.5) do
127
- block.call
128
- end
129
- end
130
- end
131
- end
132
- end
133
- end
134
103
  end
135
104
  end
136
105
 
@@ -227,7 +196,7 @@ module Sensu
227
196
  aget '/info' do
228
197
  response = {
229
198
  :sensu => {
230
- :version => Sensu::VERSION
199
+ :version => VERSION
231
200
  },
232
201
  :rabbitmq => {
233
202
  :keepalives => {
@@ -261,10 +230,10 @@ module Sensu
261
230
 
262
231
  aget '/clients' do
263
232
  response = Array.new
264
- $redis.smembers('clients').callback do |clients|
233
+ $redis.smembers('clients') do |clients|
265
234
  unless clients.empty?
266
235
  clients.each_with_index do |client_name, index|
267
- $redis.get('client:' + client_name).callback do |client_json|
236
+ $redis.get('client:' + client_name) do |client_json|
268
237
  response.push(JSON.parse(client_json))
269
238
  if index == clients.size - 1
270
239
  body response.to_json
@@ -278,7 +247,7 @@ module Sensu
278
247
  end
279
248
 
280
249
  aget %r{/clients?/([\w\.-]+)$} do |client_name|
281
- $redis.get('client:' + client_name).callback do |client_json|
250
+ $redis.get('client:' + client_name) do |client_json|
282
251
  unless client_json.nil?
283
252
  body client_json
284
253
  else
@@ -288,9 +257,9 @@ module Sensu
288
257
  end
289
258
 
290
259
  adelete %r{/clients?/([\w\.-]+)$} do |client_name|
291
- $redis.get('client:' + client_name).callback do |client_json|
260
+ $redis.get('client:' + client_name) do |client_json|
292
261
  unless client_json.nil?
293
- $redis.hgetall('events:' + client_name).callback do |events|
262
+ $redis.hgetall('events:' + client_name) do |events|
294
263
  events.each do |check_name, event_json|
295
264
  resolve_event(event_hash(event_json, client_name, check_name))
296
265
  end
@@ -302,7 +271,7 @@ module Sensu
302
271
  $redis.srem('clients', client_name)
303
272
  $redis.del('events:' + client_name)
304
273
  $redis.del('client:' + client_name)
305
- $redis.smembers('history:' + client_name).callback do |checks|
274
+ $redis.smembers('history:' + client_name) do |checks|
306
275
  checks.each do |check_name|
307
276
  $redis.del('history:' + client_name + ':' + check_name)
308
277
  end
@@ -367,10 +336,10 @@ module Sensu
367
336
 
368
337
  aget '/events' do
369
338
  response = Array.new
370
- $redis.smembers('clients').callback do |clients|
339
+ $redis.smembers('clients') do |clients|
371
340
  unless clients.empty?
372
341
  clients.each_with_index do |client_name, index|
373
- $redis.hgetall('events:' + client_name).callback do |events|
342
+ $redis.hgetall('events:' + client_name) do |events|
374
343
  events.each do |check_name, event_json|
375
344
  response.push(event_hash(event_json, client_name, check_name))
376
345
  end
@@ -387,7 +356,7 @@ module Sensu
387
356
 
388
357
  aget %r{/events/([\w\.-]+)$} do |client_name|
389
358
  response = Array.new
390
- $redis.hgetall('events:' + client_name).callback do |events|
359
+ $redis.hgetall('events:' + client_name) do |events|
391
360
  events.each do |check_name, event_json|
392
361
  response.push(event_hash(event_json, client_name, check_name))
393
362
  end
@@ -396,7 +365,7 @@ module Sensu
396
365
  end
397
366
 
398
367
  aget %r{/events?/([\w\.-]+)/([\w\.-]+)$} do |client_name, check_name|
399
- $redis.hgetall('events:' + client_name).callback do |events|
368
+ $redis.hgetall('events:' + client_name) do |events|
400
369
  event_json = events[check_name]
401
370
  unless event_json.nil?
402
371
  body event_hash(event_json, client_name, check_name).to_json
@@ -407,7 +376,7 @@ module Sensu
407
376
  end
408
377
 
409
378
  adelete %r{/events?/([\w\.-]+)/([\w\.-]+)$} do |client_name, check_name|
410
- $redis.hgetall('events:' + client_name).callback do |events|
379
+ $redis.hgetall('events:' + client_name) do |events|
411
380
  if events.include?(check_name)
412
381
  resolve_event(event_hash(events[check_name], client_name, check_name))
413
382
  accepted!
@@ -423,7 +392,7 @@ module Sensu
423
392
  client_name = post_body[:client]
424
393
  check_name = post_body[:check]
425
394
  if client_name.is_a?(String) && check_name.is_a?(String)
426
- $redis.hgetall('events:' + client_name).callback do |events|
395
+ $redis.hgetall('events:' + client_name) do |events|
427
396
  if events.include?(check_name)
428
397
  resolve_event(event_hash(events[check_name], client_name, check_name))
429
398
  accepted!
@@ -441,7 +410,7 @@ module Sensu
441
410
 
442
411
  aget '/aggregates' do
443
412
  response = Array.new
444
- $redis.smembers('aggregates').callback do |checks|
413
+ $redis.smembers('aggregates') do |checks|
445
414
  unless checks.empty?
446
415
  limit = 10
447
416
  if params[:limit]
@@ -449,7 +418,7 @@ module Sensu
449
418
  end
450
419
  unless limit.nil?
451
420
  checks.each_with_index do |check_name, index|
452
- $redis.smembers('aggregates:' + check_name).callback do |aggregates|
421
+ $redis.smembers('aggregates:' + check_name) do |aggregates|
453
422
  collection = {
454
423
  :check => check_name,
455
424
  :issued => aggregates.sort.reverse.take(limit)
@@ -470,7 +439,7 @@ module Sensu
470
439
  end
471
440
 
472
441
  aget %r{/aggregates/([\w\.-]+)$} do |check_name|
473
- $redis.smembers('aggregates:' + check_name).callback do |aggregates|
442
+ $redis.smembers('aggregates:' + check_name) do |aggregates|
474
443
  unless aggregates.empty?
475
444
  limit = 10
476
445
  if params[:limit]
@@ -488,15 +457,15 @@ module Sensu
488
457
  end
489
458
 
490
459
  adelete %r{/aggregates/([\w\.-]+)$} do |check_name|
491
- $redis.smembers('aggregates:' + check_name).callback do |aggregates|
460
+ $redis.smembers('aggregates:' + check_name) do |aggregates|
492
461
  unless aggregates.empty?
493
462
  aggregates.each do |check_issued|
494
463
  result_set = check_name + ':' + check_issued
495
464
  $redis.del('aggregation:' + result_set)
496
465
  $redis.del('aggregate:' + result_set)
497
466
  end
498
- $redis.del('aggregates:' + check_name).callback do
499
- $redis.srem('aggregates', check_name).callback do
467
+ $redis.del('aggregates:' + check_name) do
468
+ $redis.srem('aggregates', check_name) do
500
469
  no_content!
501
470
  end
502
471
  end
@@ -508,13 +477,13 @@ module Sensu
508
477
 
509
478
  aget %r{/aggregates?/([\w\.-]+)/([\w\.-]+)$} do |check_name, check_issued|
510
479
  result_set = check_name + ':' + check_issued
511
- $redis.hgetall('aggregate:' + result_set).callback do |aggregate|
480
+ $redis.hgetall('aggregate:' + result_set) do |aggregate|
512
481
  unless aggregate.empty?
513
482
  response = aggregate.inject(Hash.new) do |totals, (status, count)|
514
483
  totals[status] = Integer(count)
515
484
  totals
516
485
  end
517
- $redis.hgetall('aggregation:' + result_set).callback do |results|
486
+ $redis.hgetall('aggregation:' + result_set) do |results|
518
487
  parsed_results = results.inject(Array.new) do |parsed, (client_name, check_json)|
519
488
  check = JSON.parse(check_json, :symbolize_names => true)
520
489
  parsed.push(check.merge(:client => client_name))
@@ -543,8 +512,8 @@ module Sensu
543
512
  apost %r{/stash(?:es)?/(.*)} do |path|
544
513
  begin
545
514
  post_body = JSON.parse(request.body.read)
546
- $redis.set('stash:' + path, post_body.to_json).callback do
547
- $redis.sadd('stashes', path).callback do
515
+ $redis.set('stash:' + path, post_body.to_json) do
516
+ $redis.sadd('stashes', path) do
548
517
  created!
549
518
  end
550
519
  end
@@ -554,7 +523,7 @@ module Sensu
554
523
  end
555
524
 
556
525
  aget %r{/stash(?:es)?/(.*)} do |path|
557
- $redis.get('stash:' + path).callback do |stash_json|
526
+ $redis.get('stash:' + path) do |stash_json|
558
527
  unless stash_json.nil?
559
528
  body stash_json
560
529
  else
@@ -564,10 +533,10 @@ module Sensu
564
533
  end
565
534
 
566
535
  adelete %r{/stash(?:es)?/(.*)} do |path|
567
- $redis.exists('stash:' + path).callback do |stash_exists|
536
+ $redis.exists('stash:' + path) do |stash_exists|
568
537
  if stash_exists
569
- $redis.srem('stashes', path).callback do
570
- $redis.del('stash:' + path).callback do
538
+ $redis.srem('stashes', path) do
539
+ $redis.del('stash:' + path) do
571
540
  no_content!
572
541
  end
573
542
  end
@@ -589,7 +558,7 @@ module Sensu
589
558
  if post_body.is_a?(Array) && post_body.size > 0
590
559
  response = Hash.new
591
560
  post_body.each_with_index do |path, index|
592
- $redis.get('stash:' + path).callback do |stash_json|
561
+ $redis.get('stash:' + path) do |stash_json|
593
562
  unless stash_json.nil?
594
563
  response[path] = JSON.parse(stash_json)
595
564
  end
data/lib/sensu/base.rb CHANGED
@@ -1,52 +1,58 @@
1
1
  require 'rubygems'
2
2
 
3
3
  gem 'eventmachine', '1.0.0'
4
- gem 'amqp', '0.9.7'
5
4
 
6
5
  require 'json'
7
- require 'timeout'
8
6
  require 'time'
9
7
  require 'uri'
10
- require 'amqp'
11
8
 
12
9
  require File.join(File.dirname(__FILE__), 'constants')
10
+ require File.join(File.dirname(__FILE__), 'utilities')
13
11
  require File.join(File.dirname(__FILE__), 'cli')
14
- require File.join(File.dirname(__FILE__), 'logger')
12
+ require File.join(File.dirname(__FILE__), 'logstream')
15
13
  require File.join(File.dirname(__FILE__), 'settings')
14
+ require File.join(File.dirname(__FILE__), 'extensions')
16
15
  require File.join(File.dirname(__FILE__), 'process')
17
16
  require File.join(File.dirname(__FILE__), 'io')
17
+ require File.join(File.dirname(__FILE__), 'rabbitmq')
18
18
 
19
19
  module Sensu
20
20
  class Base
21
- attr_reader :options, :settings
22
-
23
21
  def initialize(options={})
24
- @options = Sensu::DEFAULT_OPTIONS.merge(options)
25
- setup_logging
26
- setup_settings
27
- setup_process
22
+ @options = DEFAULT_OPTIONS.merge(options)
23
+ end
24
+
25
+ def logger
26
+ stream = LogStream.new
27
+ stream.level = @options[:log_level]
28
+ if @options[:log_file]
29
+ stream.reopen(@options[:log_file])
30
+ end
31
+ stream.setup_traps
32
+ stream.logger
28
33
  end
29
34
 
30
- def setup_logging
31
- logger = Sensu::Logger.new
32
- logger.level = @options[:verbose] ? :debug : @options[:log_level] || :info
33
- logger.reopen(@options[:log_file])
34
- logger.setup_traps
35
+ def settings
36
+ settings = Settings.new
37
+ settings.load_env
38
+ settings.load_file(@options[:config_file])
39
+ settings.load_directory(@options[:config_dir])
40
+ settings.validate
41
+ settings.set_env
42
+ settings
35
43
  end
36
44
 
37
- def setup_settings
38
- @settings = Sensu::Settings.new
39
- @settings.load_env
40
- @settings.load_file(@options[:config_file])
41
- Dir[@options[:config_dir] + '/**/*.json'].each do |file|
42
- @settings.load_file(file)
45
+ def extensions
46
+ extensions = Extensions.new
47
+ if @options[:extension_dir]
48
+ extensions.require_directory(@options[:extension_dir])
43
49
  end
44
- @settings.validate
45
- @settings.set_env
50
+ extensions.load_all
51
+ extensions
46
52
  end
47
53
 
48
54
  def setup_process
49
- process = Sensu::Process.new
55
+ process = Process.new
50
56
  if @options[:daemonize]
51
57
  process.daemonize
52
58
  end
data/lib/sensu/cli.rb CHANGED
@@ -10,20 +10,23 @@ module Sensu
10
10
  exit
11
11
  end
12
12
  opts.on('-V', '--version', 'Display version') do
13
- puts Sensu::VERSION
13
+ puts VERSION
14
14
  exit
15
15
  end
16
- opts.on('-c', '--config FILE', 'Sensu JSON config FILE. Default is /etc/sensu/config.json') do |file|
16
+ opts.on('-c', '--config FILE', 'Sensu JSON config FILE. Default: /etc/sensu/config.json') do |file|
17
17
  options[:config_file] = file
18
18
  end
19
- opts.on('-d', '--config_dir DIR', 'DIR for supplemental Sensu JSON config files. Default is /etc/sensu/conf.d/') do |dir|
19
+ opts.on('-d', '--config_dir DIR', 'DIR for supplemental Sensu JSON config files. Default: /etc/sensu/conf.d/') do |dir|
20
20
  options[:config_dir] = dir
21
21
  end
22
- opts.on('-l', '--log FILE', 'Log to a given FILE. Default is to log to stdout') do |file|
22
+ opts.on('-e', '--extension_dir DIR', 'DIR for Sensu extensions (experimental)') do |dir|
23
+ options[:extension_dir] = dir
24
+ end
25
+ opts.on('-l', '--log FILE', 'Log to a given FILE. Default: STDOUT') do |file|
23
26
  options[:log_file] = file
24
27
  end
25
28
  opts.on('-v', '--verbose', 'Enable verbose logging') do
26
- options[:verbose] = true
29
+ options[:log_level] = :debug
27
30
  end
28
31
  opts.on('-b', '--background', 'Fork into the background') do
29
32
  options[:daemonize] = true
@@ -33,7 +36,7 @@ module Sensu
33
36
  end
34
37
  end
35
38
  optparse.parse!(arguments)
36
- Sensu::DEFAULT_OPTIONS.merge(options)
39
+ DEFAULT_OPTIONS.merge(options)
37
40
  end
38
41
  end
39
42
  end
data/lib/sensu/client.rb CHANGED
@@ -3,6 +3,10 @@ require File.join(File.dirname(__FILE__), 'socket')
3
3
 
4
4
  module Sensu
5
5
  class Client
6
+ include Utilities
7
+
8
+ attr_accessor :safe_mode
9
+
6
10
  def self.run(options={})
7
11
  client = self.new(options)
8
12
  EM::run do
@@ -12,41 +16,33 @@ module Sensu
12
16
  end
13
17
 
14
18
  def initialize(options={})
15
- @logger = Sensu::Logger.get
16
- base = Sensu::Base.new(options)
19
+ base = Base.new(options)
20
+ @logger = base.logger
17
21
  @settings = base.settings
22
+ base.setup_process
18
23
  @timers = Array.new
19
24
  @checks_in_progress = Array.new
25
+ @safe_mode = @settings[:client][:safe_mode] || false
20
26
  end
21
27
 
22
28
  def setup_rabbitmq
23
29
  @logger.debug('connecting to rabbitmq', {
24
30
  :settings => @settings[:rabbitmq]
25
31
  })
26
- connection_failure = Proc.new do
27
- @logger.fatal('cannot connect to rabbitmq', {
28
- :settings => @settings[:rabbitmq]
32
+ @rabbitmq = RabbitMQ.connect(@settings[:rabbitmq])
33
+ @rabbitmq.on_error do |error|
34
+ @logger.fatal('rabbitmq connection error', {
35
+ :error => error.to_s
29
36
  })
30
- @logger.fatal('SENSU NOT RUNNING!')
31
- exit 2
37
+ stop
32
38
  end
33
- @rabbitmq = AMQP.connect(@settings[:rabbitmq], {
34
- :on_tcp_connection_failure => connection_failure,
35
- :on_possible_authentication_failure => connection_failure
36
- })
37
- @rabbitmq.logger = Sensu::NullLogger.get
38
- @rabbitmq.on_tcp_connection_loss do |connection, settings|
39
- unless connection.reconnecting?
40
- @logger.warn('reconnecting to rabbitmq')
41
- connection.periodically_reconnect(5)
42
- end
39
+ @rabbitmq.before_reconnect do
40
+ @logger.warn('reconnecting to rabbitmq')
43
41
  end
44
- @rabbitmq.on_skipped_heartbeats do
45
- @logger.warn('skipped rabbitmq heartbeat')
46
- @logger.warn('rabbitmq heartbeats are not recommended for clients')
42
+ @rabbitmq.after_reconnect do
43
+ @logger.info('reconnected to rabbitmq')
47
44
  end
48
- @amq = AMQP::Channel.new(@rabbitmq)
49
- @amq.auto_recovery = true
45
+ @amq = @rabbitmq.channel
50
46
  end
51
47
 
52
48
  def publish_keepalive
@@ -102,7 +98,7 @@ module Sensu
102
98
  execute = Proc.new do
103
99
  started = Time.now.to_f
104
100
  begin
105
- check[:output], check[:status] = Sensu::IO.popen(command, 'r', check[:timeout])
101
+ check[:output], check[:status] = IO.popen(command, 'r', check[:timeout])
106
102
  rescue => error
107
103
  @logger.warn('unexpected error', {
108
104
  :error => error.to_s
@@ -158,7 +154,7 @@ module Sensu
158
154
  if @settings.check_exists?(check[:name])
159
155
  check.merge!(@settings[:checks][check[:name]])
160
156
  execute_check(check)
161
- elsif @settings[:client][:safe_mode]
157
+ elsif @safe_mode
162
158
  @logger.warn('check is not defined', {
163
159
  :check => check
164
160
  })
@@ -184,8 +180,9 @@ module Sensu
184
180
  stagger = testing? ? 0 : 2
185
181
  @settings.checks.each do |check|
186
182
  if check[:standalone]
187
- standalone_check_count = (standalone_check_count + 1) % 30
188
- @timers << EM::Timer.new(stagger * standalone_check_count) do
183
+ standalone_check_count += 1
184
+ scheduling_delay = stagger * standalone_check_count % 30
185
+ @timers << EM::Timer.new(scheduling_delay) do
189
186
  interval = testing? ? 0.5 : check[:interval]
190
187
  @timers << EM::PeriodicTimer.new(interval) do
191
188
  if @rabbitmq.connected?
@@ -200,14 +197,14 @@ module Sensu
200
197
 
201
198
  def setup_sockets
202
199
  @logger.debug('binding client tcp socket')
203
- EM::start_server('127.0.0.1', 3030, Sensu::Socket) do |socket|
200
+ EM::start_server('127.0.0.1', 3030, Socket) do |socket|
204
201
  socket.protocol = :tcp
205
202
  socket.logger = @logger
206
203
  socket.settings = @settings
207
204
  socket.amq = @amq
208
205
  end
209
206
  @logger.debug('binding client udp socket')
210
- EM::open_datagram_socket('127.0.0.1', 3030, Sensu::Socket) do |socket|
207
+ EM::open_datagram_socket('127.0.0.1', 3030, Socket) do |socket|
211
208
  socket.protocol = :udp
212
209
  socket.logger = @logger
213
210
  socket.settings = @settings
@@ -265,19 +262,5 @@ module Sensu
265
262
  end
266
263
  end
267
264
  end
268
-
269
- private
270
-
271
- def testing?
272
- File.basename($0) == 'rake'
273
- end
274
-
275
- def retry_until_true(wait=0.5, &block)
276
- EM::Timer.new(wait) do
277
- unless block.call
278
- retry_until_true(wait, &block)
279
- end
280
- end
281
- end
282
265
  end
283
266
  end