Class: Breakers::Service

Inherits:
Object
  • Object
show all
Defined in:
lib/breakers/service.rb

Overview

A service defines a backend system that your application relies upon. This class allows you to configure the outage detection for a service as well as to define which requests belong to it.

Constant Summary collapse

DEFAULT_OPTS =
{
  seconds_before_retry: 60,
  error_threshold: 50,
  data_retention_seconds: 60 * 60 * 24 * 30
}.freeze

Instance Method Summary collapse

Constructor Details

#initialize(opts) ⇒ Service

Create a new service

Parameters:

  • opts (Hash)

    the options to create the service with

Options Hash (opts):

  • :name (String)

    The name of the service for reporting and logging purposes

  • :request_matcher (Proc)

    A proc taking a Faraday::Env as an argument that returns true if the service handles that request

  • :seconds_before_retry (Integer)

    The number of seconds to wait after an outage begins before testing with a new request

  • :error_threshold (Integer)

    The percentage of errors over the last two minutes that indicates an outage

  • :data_retention_seconds (Integer)

    The number of seconds to retain success and error data in Redis

  • :exception_handler (Proc)

    A proc taking an exception and returns true if it represents an error on the service



21
22
23
# File 'lib/breakers/service.rb', line 21

def initialize(opts)
  @configuration = DEFAULT_OPTS.merge(opts)
end

Instance Method Details

#add_errorObject

Indicate that an error has occurred and potentially create an outage



55
56
57
58
# File 'lib/breakers/service.rb', line 55

def add_error
  increment_key(key: errors_key)
  maybe_create_outage
end

#add_successObject

Indicate that a successful response has occurred



61
62
63
# File 'lib/breakers/service.rb', line 61

def add_success
  increment_key(key: successes_key)
end

#begin_forced_outage!Object

Force an outage to begin on the service. Forced outages are not periodically retested.



66
67
68
# File 'lib/breakers/service.rb', line 66

def begin_forced_outage!
  Outage.create(service: self, forced: true)
end

#end_forced_outage!Object

End a forced outage on the service.



71
72
73
74
75
76
# File 'lib/breakers/service.rb', line 71

def end_forced_outage!
  latest = Outage.find_latest(service: self)
  if latest.forced?
    latest.end!
  end
end

#errors_in_range(start_time:, end_time:, sample_minutes: 60) ⇒ Array[Hash]

Return data about the failed request counts in the time range

Parameters:

  • start_time (Time)

    the beginning of the range

  • end_time (Time)

    the end of the range

  • sample_minutes (Integer) (defaults to: 60)

    the rate at which to sample the data

Returns:

  • (Array[Hash])

    a list of hashes in the form: { count: Integer, time: Unix Timestamp }



112
113
114
# File 'lib/breakers/service.rb', line 112

def errors_in_range(start_time:, end_time:, sample_minutes: 60)
  values_in_range(start_time: start_time, end_time: end_time, type: :errors, sample_minutes: sample_minutes)
end

#exception_represents_server_error?(exception) ⇒ Boolean

Returns true if a given exception represents an error with the service

Returns:

  • (Boolean)

    is it an error?



50
51
52
# File 'lib/breakers/service.rb', line 50

def exception_represents_server_error?(exception)
  @configuration[:exception_handler]&.call(exception)
end

#handles_request?(request_env:) ⇒ Boolean

Given a Faraday::Env, return true if this service handles the request, via its matcher

Parameters:

  • request_env (Faraday::Env)

    the request environment

Returns:

  • (Boolean)

    should the service handle the request



36
37
38
# File 'lib/breakers/service.rb', line 36

def handles_request?(request_env:)
  @configuration[:request_matcher].call(request_env)
end

#latest_outageObject

Return the most recent outage on the service



79
80
81
# File 'lib/breakers/service.rb', line 79

def latest_outage
  Outage.find_latest(service: self)
end

#nameString

Get the name of the service

Returns:

  • (String)

    the name



28
29
30
# File 'lib/breakers/service.rb', line 28

def name
  @configuration[:name]
end

#outages_in_range(start_time:, end_time:) ⇒ Array[Outage]

Return a list of all outages in the given time range

Parameters:

  • start_time (Time)

    the beginning of the range

  • end_time (Time)

    the end of the range

Returns:

  • (Array[Outage])

    a list of outages that began in the range



88
89
90
91
92
93
94
# File 'lib/breakers/service.rb', line 88

def outages_in_range(start_time:, end_time:)
  Outage.in_range(
    service: self,
    start_time: start_time,
    end_time: end_time
  )
end

#seconds_before_retryInteger

Get the seconds before retry parameter

Returns:

  • (Integer)

    the value



43
44
45
# File 'lib/breakers/service.rb', line 43

def seconds_before_retry
  @configuration[:seconds_before_retry]
end

#successes_in_range(start_time:, end_time:, sample_minutes: 60) ⇒ Array[Hash]

Return data about the successful request counts in the time range

Parameters:

  • start_time (Time)

    the beginning of the range

  • end_time (Time)

    the end of the range

  • sample_minutes (Integer) (defaults to: 60)

    the rate at which to sample the data

Returns:

  • (Array[Hash])

    a list of hashes in the form: { count: Integer, time: Unix Timestamp }



102
103
104
# File 'lib/breakers/service.rb', line 102

def successes_in_range(start_time:, end_time:, sample_minutes: 60)
  values_in_range(start_time: start_time, end_time: end_time, type: :successes, sample_minutes: sample_minutes)
end