Class: Wait

Inherits:
Object
  • Object
show all
Includes:
Dependency, Log::Dependency
Defined in:
lib/wait/log.rb,
lib/wait/wait.rb,
lib/wait/controls/time.rb

Direct Known Subclasses

Substitute::Wait

Defined Under Namespace

Modules: Controls, Defaults, Substitute, Telemetry Classes: Log

Constant Summary collapse

Error =
Class.new(RuntimeError)
NoBlockError =
Class.new(Error)
TimeoutError =
Class.new(Error)
ResultTypeError =
Class.new(Error)

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.buildObject



13
14
15
16
17
# File 'lib/wait/wait.rb', line 13

def self.build
  instance = new
  instance.configure
  instance
end

.call(interval_milliseconds: nil, timeout_milliseconds: nil, &condition) ⇒ Object



30
31
32
33
# File 'lib/wait/wait.rb', line 30

def self.call(interval_milliseconds: nil, timeout_milliseconds: nil, &condition)
  instance = build
  instance.call(interval_milliseconds: interval_milliseconds, timeout_milliseconds: timeout_milliseconds, &condition)
end

.configure(receiver, attr_name: nil) ⇒ Object



19
20
21
22
23
# File 'lib/wait/wait.rb', line 19

def self.configure(receiver, attr_name: nil)
  attr_name ||= :wait
  instance = build
  receiver.public_send("#{attr_name}=", instance)
end

.register_telemetry_sink(cycle) ⇒ Object



126
127
128
129
130
# File 'lib/wait/wait.rb', line 126

def self.register_telemetry_sink(cycle)
  sink = Telemetry.sink
  cycle.telemetry.register(sink)
  sink
end

Instance Method Details

#call(interval_milliseconds: nil, timeout_milliseconds: nil, &condition) ⇒ Object



35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/wait/wait.rb', line 35

def call(interval_milliseconds: nil, timeout_milliseconds: nil, &condition)
  interval_milliseconds ||= Defaults.interval_milliseconds

  if condition.nil?
    raise NoBlockError, "Wait must be actuated with a block"
  end

  stop_time = nil
  stop_time_iso8601 = nil
  if not timeout_milliseconds.nil?
    stop_time = clock.now + (timeout_milliseconds.to_f / 1000.0)
    stop_time_iso8601 = clock.iso8601(stop_time, precision: 5)
  end

  logger.trace { "Cycling (Interval Milliseconds: #{interval_milliseconds.inspect}, Timeout Milliseconds: #{timeout_milliseconds.inspect}, Stop Time: #{stop_time_iso8601.inspect})" }

  cycle = -1
  result = nil
  loop do
    cycle += 1
    telemetry.record(:cycle, cycle)

    result, elapsed_milliseconds = evaluate_condition(cycle, &condition)

    if result.nil?
      result = false
    end

    if not (result.is_a?(TrueClass) || result.is_a?(FalseClass))
      raise ResultTypeError, "The block result must be boolean (Result: #{result.inspect})"
    end

    if result == true
      logger.debug { "Cycle condition is met (Cycle: #{cycle})" }
      telemetry.record(:condition_satisfied)
      break
    end

    delay(interval_milliseconds, elapsed_milliseconds)

    if !timeout_milliseconds.nil?
      now = clock.now
      if now >= stop_time
        logger.debug { "Timeout has lapsed (Cycle: #{cycle}, Stop Time: #{stop_time_iso8601}, Timeout Milliseconds: #{timeout_milliseconds.inspect})" }
        telemetry.record(:timed_out, now)
        break
      end
    end
  end

  logger.debug { "Cycled (Cycles: #{cycle + 1}, Interval Milliseconds: #{interval_milliseconds.inspect}, Timeout Milliseconds: #{timeout_milliseconds.inspect}, Stop Time: #{stop_time_iso8601})" }

  cycle_count = cycle + 1

  return cycle_count
end

#configureObject



25
26
27
28
# File 'lib/wait/wait.rb', line 25

def configure
  Clock::UTC.configure(self)
  ::Telemetry.configure(self)
end

#delay(interval_milliseconds, elapsed_milliseconds) ⇒ Object



107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/wait/wait.rb', line 107

def delay(interval_milliseconds, elapsed_milliseconds)
  delay_milliseconds = interval_milliseconds - elapsed_milliseconds

  logger.trace { "Delaying (Delay Milliseconds: #{delay_milliseconds}, Interval Milliseconds: #{interval_milliseconds}, Elapsed Milliseconds: #{elapsed_milliseconds})" }

  if delay_milliseconds <= 0
    logger.debug { "Elapsed time exceeds or equals interval. Not delayed. (Delay Milliseconds: #{delay_milliseconds}, Interval Milliseconds: #{interval_milliseconds}, Elapsed Milliseconds: #{elapsed_milliseconds})" }
    return
  end

  delay_seconds = (delay_milliseconds.to_f / 1000.0)

  sleep delay_seconds

  telemetry.record(:delayed, delay_milliseconds)

  logger.debug { "Finished delaying (Delay Milliseconds: #{delay_milliseconds}, Interval Milliseconds: #{interval_milliseconds}, Elapsed Milliseconds: #{elapsed_milliseconds})" }
end

#evaluate_condition(cycle, &condition) ⇒ Object



92
93
94
95
96
97
98
99
100
101
102
103
104
105
# File 'lib/wait/wait.rb', line 92

def evaluate_condition(cycle, &condition)
  condition_start_time = clock.now

  logger.trace { "Evaluating condition (Cycle: #{cycle}, Start Time: #{clock.iso8601(condition_start_time, precision: 5)})" }

  result = condition.call(cycle)

  condition_end_time = clock.now
  elapsed_milliseconds = clock.elapsed_milliseconds(condition_start_time, condition_end_time)

  logger.debug { "Evaluated condition (Cycle: #{cycle}, Elapsed Milliseconds: #{elapsed_milliseconds}, Start Time: #{clock.iso8601(condition_start_time, precision: 5)}, End Time: #{clock.iso8601(condition_end_time, precision: 5)})" }

  [result, elapsed_milliseconds]
end