Repository URL to install this package:
|
Version:
0.2.0.0 ▾
|
class Cycle
dependency :clock, Clock::UTC
dependency :telemetry, Telemetry
dependency :logger, Log
attr_writer :delay_milliseconds
attr_writer :delay_condition
def delay_milliseconds
@delay_milliseconds ||= Defaults.delay_milliseconds
end
def delay_condition
@delay_condition ||= Defaults.delay_condition
end
initializer :timeout_milliseconds
def self.build(delay_milliseconds: nil, timeout_milliseconds: nil, delay_condition: nil)
if delay_milliseconds.nil? && timeout_milliseconds.nil?
return none
end
new(timeout_milliseconds).tap do |instance|
instance.delay_milliseconds = delay_milliseconds
instance.delay_condition = delay_condition
instance.configure
end
end
def self.configure(receiver, attr_name: nil, delay_milliseconds: nil, timeout_milliseconds: nil, delay_condition: nil, cycle: nil)
attr_name ||= :cycle
if !cycle.nil?
instance = cycle
else
instance = build(delay_milliseconds: delay_milliseconds, timeout_milliseconds: timeout_milliseconds, delay_condition: delay_condition)
end
receiver.public_send "#{attr_name}=", instance
end
def self.none
None.build
end
def configure
Clock::UTC.configure self
::Telemetry.configure self
Log.configure self
end
def self.call(delay_milliseconds: nil, timeout_milliseconds: nil, delay_condition: nil, &action)
instance = build(delay_milliseconds: delay_milliseconds, timeout_milliseconds: timeout_milliseconds, delay_condition: delay_condition)
instance.call(&action)
end
def call(&action)
stop_time = nil
if !timeout_milliseconds.nil?
stop_time = clock.now + (timeout_milliseconds.to_f / 1000.0)
end
logger.trace "Cycling (Delay Milliseconds: #{delay_milliseconds}, Timeout Milliseconds: #{timeout_milliseconds.inspect}, Stop Time: #{clock.iso8601(stop_time)})"
iteration = -1
result = nil
loop do
iteration += 1
telemetry.record :cycle, iteration
result = invoke(iteration, &action)
if delay_condition.(result)
logger.debug "No results (Iteration: #{iteration})"
delay
else
logger.debug "Got results (Iteration: #{iteration})"
telemetry.record :got_result
break
end
if !timeout_milliseconds.nil?
now = clock.now
if now >= stop_time
logger.debug "Timeout has lapsed (Iteration: #{iteration}, Stop Time: #{clock.iso8601(stop_time)}, Timeout Milliseconds: #{timeout_milliseconds})"
telemetry.record :timed_out, now
break
end
end
end
logger.debug "Cycled (Iterations: #{iteration}, Delay Milliseconds: #{delay_milliseconds}, Timeout Milliseconds: #{timeout_milliseconds.inspect}, Stop Time: #{clock.iso8601(stop_time)})"
return result
end
def invoke(iteration, &action)
logger.trace "Invoking action (Iteration: #{iteration})"
result = action.call
telemetry.record :invoked_action
logger.debug "Invoked action (Iteration: #{iteration})"
result
end
def delay
logger.trace "Delaying (Milliseconds: #{delay_milliseconds})"
delay_seconds = (delay_milliseconds.to_f / 1000.0)
sleep delay_seconds
telemetry.record :delayed, delay_milliseconds
logger.debug "Finished delaying (Milliseconds: #{delay_milliseconds})"
end
def self.register_telemetry_sink(writer)
sink = Telemetry.sink
writer.telemetry.register sink
sink
end
module Telemetry
class Sink
include ::Telemetry::Sink
record :cycle
record :invoked_action
record :got_result
record :delayed
record :timed_out
end
def self.sink
Sink.new
end
end
module Substitute
def self.build
Cycle::None.build.tap do |instance|
sink = Cycle.register_telemetry_sink(instance)
instance.telemetry_sink = sink
end
end
end
class None < Cycle
attr_accessor :telemetry_sink
def self.build(delay_milliseconds: nil, timeout_milliseconds: nil, delay_condition: nil)
new(timeout_milliseconds).tap do |instance|
instance.configure
end
end
def call(&action)
action.call
end
end
module Defaults
def self.delay_milliseconds
200
end
def self.delay_condition
lambda do |result|
if result.respond_to? :empty?
result.empty?
else
result.nil?
end
end
end
end
end