Skip to content

Instantly share code, notes, and snippets.

@tfausak
Created August 17, 2014 18:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tfausak/5f3a4419ba5241757ca7 to your computer and use it in GitHub Desktop.
Save tfausak/5f3a4419ba5241757ca7 to your computer and use it in GitHub Desktop.
Exploratory attempt at storing all stoplight runs.
class Run
attr_reader :state
attr_reader :exception
attr_reader :time
def initialize(state, exception = nil, time = nil)
@state = state
@exception = exception
@time = time.nil? ? Time.now : time
end
def failure?
!exception.nil?
end
end
class Stoplight
STATE_GREEN = 'green'.freeze
STATE_YELLOW = 'yellow'.freeze
STATE_RED = 'red'.freeze
DEFAULT_ALLOWED_EXCEPTIONS = [
NoMemoryError,
ScriptError,
SignalException,
SystemExit
]
DEFAULT_FALLBACK = -> { fail NotImplementedError }
DEFAULT_HEURISTIC = lambda do |runs|
failures = runs.reverse.take_while(&:failure?)
threshold = 3
return STATE_GREEN if failures.size < threshold
failure = failures.first
timeout = 60
return STATE_YELLOW if Time.now - failure.time > timeout
STATE_RED
end
attr_reader :allowed_exceptions
attr_reader :code
attr_reader :fallback
attr_reader :heuristic
attr_reader :name
attr_reader :runs
def initialize(name, &code)
fail ArgumentError unless block_given?
@code = code
@name = name.to_s
self.allowed_exceptions = DEFAULT_ALLOWED_EXCEPTIONS
self.fallback = DEFAULT_FALLBACK
self.heuristic = DEFAULT_HEURISTIC
@runs = []
end
def run
case state
when STATE_GREEN, STATE_YELLOW
run_code
when STATE_RED
run_fallback
else
fail ArgumentError
end
end
def state
heuristic.call(runs)
end
def allowed_exceptions=(allowed_exceptions)
@allowed_exceptions = allowed_exceptions.to_a
end
def fallback=(fallback)
@fallback = fallback.to_proc
end
def heuristic=(heuristic)
@heuristic = heuristic.to_proc
end
private
def exception_allowed?(exception)
allowed_exceptions.any? { |klass| exception.is_a?(klass) }
end
def run_code
code.call.tap { runs.push(Run.new(state)) }
rescue Exception => exception
runs.push(Run.new(state, (exception unless exception_allowed?(exception))))
raise
end
def run_fallback
fallback.call
ensure
runs.push(Run.new(state))
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment