# EbisuConnection
[![Gem Version](https://badge.fury.io/rb/ebisu_connection.svg)](http://badge.fury.io/rb/ebisu_connection) [![Build Status](https://travis-ci.org/tsukasaoishi/ebisu_connection.svg?branch=master)](https://travis-ci.org/tsukasaoishi/ebisu_connection) [![Code Climate](https://codeclimate.com/github/tsukasaoishi/ebisu_connection/badges/gpa.svg)](https://codeclimate.com/github/tsukasaoishi/ebisu_connection)

EbisuConnection allows access to replica servers.  
You could assign a performance weight to each replica server.

```
Rails ------------ Master DB
             |
             | 
             +---- Replica1 DB (weight 10)
             |
             |
             +---- Replica2 DB (weight 20)
```

If you could put a load balancer in front of replica servers, should use [FreshConnection](https://github.com/tsukasaoishi/fresh_connection).

## Usage
### Access to Replica
Read query goes to the replica server.

```ruby
Article.where(:id => 1)
```

### Access to Master
If read query want to access to the master server, use `read_master`.  
In before version 0.3.1, can use `readonly(false)`.

```ruby
Article.where(:id => 1).read_master
```

In transaction, All queries go to the master server.

```ruby
Article.transaction do
  Article.where(:id => 1)
end
```

Create, Update and Delete queries go to the master server.

```ruby
article = Article.create(...)
article.title = "FreshConnection"
article.save
article.destory
```

## Support ActiveRecord version
EbisuConnection supports ActiveRecord version 4.2 or later.
If you are using Rails 4.1 or 4.0, you can use EbisuConnection version 2.1.0 or before.
If you are using Rails 3.2, could use EbisuConnection version 1.0.0 or before.

## Support DB
EbisuConnection supports MySQL and PostgreSQL.

## Installation

Add this line to your application's Gemfile:

```ruby
gem 'ebisu_connection'
```

And then execute:

```
$ bundle
```

Or install it yourself as:

```
$ gem install ebisu_connection
```

## Config

config/database.yml

```yaml
production:
  adapter: mysql2
  encoding: utf8
  reconnect: true
  database: kaeru
  pool: 5
  username: master
  password: master
  host: localhost
  socket: /var/run/mysqld/mysqld.sock

  replica:
    username: replica
    password: replica
    host: replica
```

```replica``` is a config to connect to replica servers.  
Others will use the master server settings.  
  
Config of each replica server fill out to `config/replica.yml`

```yaml
production:
  - "replica1, 10"
  - "replica2, 20"
  -
    host: "replica3"
    weight: 30
```

If ``config/replica.yml`` changed, it is reflected dynamic. Application doesn't need restart.

```yaml
"hostname, weight"
```

String format is it. You can write config with hash.

### use multiple replica servers group
If you may want to user multiple replica group, write multiple replica group to config/database.yml. 

```yaml
production:
  adapter: mysql2
  encoding: utf8
  reconnect: true
  database: kaeru
  pool: 5
  username: master
  password: master
  host: localhost
  socket: /var/run/mysqld/mysqld.sock

  replica:
    username: replica
    password: replica
    host: replica

  admin_replica:
    username: replica
    password: replica
    host: admin_replica
```

Config of each replica server fill out to `config/replica.yml`

```yaml
production:
  replica:
    - "replica1, 10"
    - "replica2, 20"
    -
      host: "replica3"
      weight: 30
  admin_replica:
    - "replica4, 10"
    - "replica5, 20"
```

And call establish_fresh_connection method in model that access to ```admin_replica``` replica group.

```ruby
class AdminUser < ActiveRecord::Base
  establish_fresh_connection :admin_replica
end
```

The children is access to same replica group of parent.

```ruby
class Parent < ActiveRecord::Base
  establish_fresh_connection :admin_replica
end

class AdminUser < Parent
end

class Benefit < Parent
end
```

AdminUser and Benefit access to ```admin_replica``` replica group.


### Declare model that doesn't use replica db

```ruby
class SomethingModel < ActiveRecord::Base
  master_db_only!
end
```

If model that always access to master servers is exist, You may want to write ```master_db_only!```  in model.
The model that master_db_only model's child is always access to master db.

### for Unicorn

```ruby
before_fork do |server, worker|
  ...
  ActiveRecord::Base.clear_all_replica_connections!
  ...
end

after_fork do |server, worker|
  ...
  ActiveRecord::Base.establish_fresh_connection
  ...
end
```

## Contributing

1. Fork it
2. Create your feature branch (`git checkout -b my-new-feature`)
3. Commit your changes (`git commit -am 'Add some feature'`)
4. Push to the branch (`git push origin my-new-feature`)
5. Create new Pull Request

## Test

I'm glad that you would do test!
To run the test suite, you need mysql installed.
How to setup your test environment.

```bash
./bin/setup
```

This command run the spec suite for all rails versions supported.

```base
./bin/test
```