Class: Freno::Client

Inherits:
Object
  • Object
show all
Defined in:
lib/freno/client.rb,
lib/freno/client/result.rb,
lib/freno/client/request.rb,
lib/freno/client/version.rb,
lib/freno/client/preconditions.rb,
lib/freno/client/requests/check.rb,
lib/freno/client/requests/check_read.rb,
lib/freno/client/requests/replication_delay.rb

Defined Under Namespace

Modules: Preconditions, Requests Classes: DecorationError, Request, Result

Constant Summary collapse

REQUESTS =
{
  check: Requests::Check,
  check_read: Requests::CheckRead,
  replication_delay: Requests::ReplicationDelay
}.freeze
VERSION =
Gem::Version.new("0.9.0")

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(faraday) {|_self| ... } ⇒ Client

Creates a new instance of the client, that uses faraday to make http calls.

If most of the times you are going to ask Freno about the same app and/or storage name, you can tell the client to use some defaults, and override them as necessary.

Examples a ruby client that by default asks Freno for throttling information about ‘:my_app` accessing `:my_cluster` storage.

```ruby
freno = Freno::Client.new(faraday) do |client|
  client.default_store_name = :my_cluster
  client.default_app        = :my_app
end
```

Any options set on the Client are passed through to the initialization of each request:

```ruby
freno = Freno::Client.new(faraday) do |client|
  client.options = { raise_on_timeout: false }
end
```

These default options can be overridden per request. The given options
are merged into the defaults. The request below would be performed with
the options: `{ raise_on_timeout: false, low_priority: true }`

```ruby
freno = Freno::Client.new(faraday) do |client|
  client.options = { raise_on_timeout: false }
end

freno.check?(options: { low_priority: true })
```

Yields:

  • (_self)

Yield Parameters:

  • _self (Freno::Client)

    the object that the method was called on



57
58
59
60
61
62
63
64
65
# File 'lib/freno/client.rb', line 57

def initialize(faraday)
  @faraday            = faraday
  @default_store_type = :mysql
  @options            = {}
  @decorators         = {}
  @decorated_requests = {}

  yield self if block_given?
end

Instance Attribute Details

#decorated_requestsObject (readonly)

Returns the value of attribute decorated_requests.



18
19
20
# File 'lib/freno/client.rb', line 18

def decorated_requests
  @decorated_requests
end

#decoratorsObject (readonly)

Returns the value of attribute decorators.



18
19
20
# File 'lib/freno/client.rb', line 18

def decorators
  @decorators
end

#default_appObject

Returns the value of attribute default_app.



19
20
21
# File 'lib/freno/client.rb', line 19

def default_app
  @default_app
end

#default_store_nameObject

Returns the value of attribute default_store_name.



19
20
21
# File 'lib/freno/client.rb', line 19

def default_store_name
  @default_store_name
end

#default_store_typeObject

Returns the value of attribute default_store_type.



19
20
21
# File 'lib/freno/client.rb', line 19

def default_store_type
  @default_store_type
end

#faradayObject (readonly)

Returns the value of attribute faraday.



18
19
20
# File 'lib/freno/client.rb', line 18

def faraday
  @faraday
end

#optionsObject

Returns the value of attribute options.



19
20
21
# File 'lib/freno/client.rb', line 19

def options
  @options
end

Instance Method Details

#check(app: default_app, store_type: default_store_type, store_name: default_store_name, options: {}) ⇒ Object

Provides an interface to Freno“s check request

See github.com/github/freno/blob/master/doc/http.md#check-request

Returns Result



73
74
75
# File 'lib/freno/client.rb', line 73

def check(app: default_app, store_type: default_store_type, store_name: default_store_name, options: {})
  perform :check, app: app, store_type: store_type, store_name: store_name, options: self.options.merge(options)
end

#check?(app: default_app, store_type: default_store_type, store_name: default_store_name, options: {}) ⇒ Boolean

Determines whether Freno considers it“s OK to write to masters

Returns true or false.

Returns:

  • (Boolean)


126
127
128
# File 'lib/freno/client.rb', line 126

def check?(app: default_app, store_type: default_store_type, store_name: default_store_name, options: {})
  check(app: app, store_type: store_type, store_name: store_name, options: self.options.merge(options)).ok?
end

#check_read(threshold:, app: default_app, store_type: default_store_type, store_name: default_store_name, options: {}) ⇒ Object

Provides an interface to Freno“s check-read request

See github.com/github/freno/blob/master/doc/http.md#specialized-requests

Returns Result



83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/freno/client.rb', line 83

def check_read(
  threshold:,
  app: default_app,
  store_type: default_store_type,
  store_name: default_store_name,
  options: {}
)
  perform(
    :check_read,
    threshold: threshold,
    app: app,
    store_type: store_type,
    store_name: store_name,
    options: self.options.merge(options)
  )
end

#check_read?(threshold:, app: default_app, store_type: default_store_type, store_name: default_store_name, options: {}) ⇒ Boolean

Determines whether it“s OK to read from replicas as replication delay is below the given threshold.

Returns true or false.

Returns:

  • (Boolean)


135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
# File 'lib/freno/client.rb', line 135

def check_read?(
  threshold:,
  app: default_app,
  store_type: default_store_type,
  store_name: default_store_name,
  options: {}
)
  check_read(
    threshold: threshold,
    app: app,
    store_type: store_type,
    store_name: store_name,
    options: self.options.merge(options)
  ).ok?
end

#decorate(request_or_all, with:) ⇒ Object

Configures the client to extend the functionality of part or all the API by means of decorators.

A decorator is any object that has a ‘:request` accessor and can forward the execution of `perform` to it.

Examples:

The following is a decorator implementing a read-trough cache.

“‘ruby class Cache

attr_accessor :request

def initialize(cache, ttl)
  @cache = cache
  @ttl = ttl
end

def perform(**kwargs)
  @cache.fetch("freno:client:v1:#{args.hash}", ttl: @ttl) do
    request.perform(kwargs)
  end
end

end “‘

You can use it to decorate a single kind of request to freno:

“‘ruby freno = Freno::Client.new(faraday) do |client|

client.decorate :replication_delay, with: Cache.new(App.cache, App.config.ttl)

end “‘

Or every kind of request:

“‘ruby freno = Freno::Client.new(faraday) do |client|

client.decorate :all, with: Cache.new(App.cache, App.config.ttl)

end “‘

Additionally, decorators can be composed in multiple ways. The following client applies logging and instrumentation to all the requests, and it also applies caching, before the previous concerns, to ‘replication_delay` requests.

“‘ruby freno = Freno::Client.new(faraday) do |client|

client.decorate :replication_delay, with: caching
client.decorate :all, with: [logging, instrumentation]

end “‘



205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
# File 'lib/freno/client.rb', line 205

def decorate(request_or_all, with:)
  requests =
    if request_or_all == :all
      REQUESTS.keys
    else
      Array(request_or_all)
    end

  with = Array(with)
  validate!(with)

  requests.each do |request|
    decorators[request] ||= []
    decorators[request] += with
    decorated_requests[request] = nil
  end
end

#replication_delay(app: default_app, store_type: default_store_type, store_name: default_store_name, options: {}) ⇒ Object

Implements a specific check request to retrieve the consolidated replication delay

See github.com/github/freno/blob/master/doc/http.md#get-method

Returns Float indicating the replication delay in seconds as reported by Freno.



107
108
109
110
111
112
113
114
115
116
117
118
119
120
# File 'lib/freno/client.rb', line 107

def replication_delay(
  app: default_app,
  store_type: default_store_type,
  store_name: default_store_name,
  options: {}
)
  perform(
    :replication_delay,
    app: app,
    store_type: store_type,
    store_name: store_name,
    options: self.options.merge(options)
  )
end