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.
```ruby
freno = Freno::Client.new(faraday) do |client|
client.default_store_name = :my_cluster
client.default_app = :my_app
end
freno.check?
# => true (Freno thinks that `my_app` can write to `main` storage)
# => false (Freno thinks that `another_app` should not write to `another_storage`)
```
### What can I do with the client?
#### Asking whether an app can write to a certain storage. ([`check` requests](https://github.com/github/freno/blob/master/doc/http.md#check-requests))
If we want to get a deep sense on why freno allowed or not, writing to a certain storage.
#### Asking whether replication delay is below a certain threshold. ([`check-read` requests](https://github.com/github/freno/blob/master/doc/http.md#specialized-requests))
```ruby
result = freno.check_read(threshold: 0.5, app: :my_app, store_name: :my_cluster)
# => true or false (a shortcut for `check_read.ok?`)
```
#### Asking what's the replication delay
Freno's response to [`GET /check`](https://github.com/github/freno/blob/master/doc/http.md#get-method) includes the replication delay value in seconds. The `replication_delay` method in the client returns this information.
applies logging and instrumentation to all the requests, and it also applies caching, **before** the previous concerns, to `replication_delay` requests.
In the above example, `Freno::Throttler#throttle(context, &block)` will check freno to determine whether is OK to proceed with the given block. If so, the block will be executed immediately, otherwise the throttler will sleep and try
A Throttler instance will make calls to freno on behalf of the given `app`,
using the given `client` (an instance of `Freno::Client`).
You optionally provide the time you want the throttler to sleep in case the check to freno fails, this is `wait_seconds`.
If replication lags badly, you can control until when you want to keep sleeping
and retrying the check by setting `max_wait_seconds`. When that times out, the throttle will raise a `Freno::Throttler::WaitedTooLong` error.
#### Instrumenting the throttler
You can also configure the throttler with an `instrumenter` collaborator to subscribe to events happening during the `throttle` call.
An instrumenter is an object that responds to `instrument(event_name, payload = {})` to receive events from the throttler. One could use `ActiveSupport::Notifications` as an instrumenter and subscribe to "freno.*" events somewhere else in the application, or implement one like the following to push some metrics to a stats system.
The throttler can also receive a `circuit_breaker` object to implement resiliency.
With that information it receives, the circuit breaker determines whether or not to allow the next request. A circuit is said to be open when the next request is not allowed; and it's said to be closed when the next request is allowed
If the throttler waited too long, or an unexpected error happened; the circuit breaker will receive a `failure`. If in contrast it succeeded, the circuit breaker will receive a `success` message.
Once the circuit is open, the throttler will not try to throttle calls, an instead throw a `Freno::Throttler::CircuitOpen`
The following is a simple per-process circuit breaker implementation:
You can create your own mapper, which is just an callable object (like a Proc, or any other object that responds to `call(context)`). The following is a mapper that knows how to throttle access to certain tables and shards.
After checking out the repo, run `bin/setup` to install dependencies. Then, run `bin/test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
This repository is open to [contributions](CONTRIBUTING.md). Contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.