ebisu_connection 1.0.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6ca70a47990e4d8b4785fd2d744777cce70ca488
4
- data.tar.gz: deb891cf866a57e0fa9945215737bbe73774469e
3
+ metadata.gz: 764c768519c8100f8cebb21c2f82a2f7366b9027
4
+ data.tar.gz: fe2a33cd780b591989c14007ec9fd37fd14f8702
5
5
  SHA512:
6
- metadata.gz: 073399cd8859740d5a14c69b4932f4615438841012adae7f4bd95f909c7f62754dca313e9ccd958d3863c6932b16cf5142adfb7a75a0d95ebfb27aeddd0fe425
7
- data.tar.gz: 8656575ecfac9e40ef0b9b56a5ae34f836e174467c84524ae5e617b48fab1cf200308a72bb8de5573f6a76a2a45920852ec401904daf10b163467250afca86b7
6
+ metadata.gz: be9cbf840dbeca58b62dae564ccd7108e03d8140c9a359e2a0c75ab52ae8a0406f20cbef725fc8fcef0d818fa85d3270883621955584e7552abb0e5739ed09f7
7
+ data.tar.gz: 4ef3c1940b977e53318ea19cef4c27b5ba80fa8d20377d8aecbd319fd5bf75387a9de8c3cb3893f09b4a338d17ce8afd3a512098d113f89911c7db54d418697b
data/.travis.yml CHANGED
@@ -1,11 +1,15 @@
1
1
  language: ruby
2
2
  before_install:
3
3
  - gem install bundler
4
+ services:
5
+ - mysql
6
+ - postgresql
4
7
  before_script:
5
- - mysql -e 'create database ebisu_connection_test;'
6
- - mysql -e 'create database ebisu_connection_test_master;'
7
- - mysql -e 'create database ebisu_connection_test_slave;'
8
8
  - bundle update
9
+ - cp test/config/database_postgresql.yml.travis test/config/database_postgresql.yml
10
+ - psql -c 'create database fresh_connection_test_master;' -U postgres
11
+ - psql -c 'create database fresh_connection_test_slave1;' -U postgres
12
+ - psql -c 'create database fresh_connection_test_slave2;' -U postgres
9
13
  cache: bundler
10
14
  rvm:
11
15
  - 2.0.0
@@ -14,10 +18,25 @@ rvm:
14
18
  - 2.3.0
15
19
  - ruby-head
16
20
  gemfile:
17
- - gemfiles/rails3.gemfile
18
21
  - gemfiles/rails40.gemfile
19
22
  - gemfiles/rails41.gemfile
20
23
  - gemfiles/rails42.gemfile
24
+ - gemfiles/rails50.gemfile
25
+ matrix:
26
+ exclude:
27
+ - rvm: 2.3.0
28
+ gemfile: gemfiles/rails40.gemfile
29
+ - rvm: ruby-head
30
+ gemfile: gemfiles/rails40.gemfile
31
+ - rvm: 2.0.0
32
+ gemfile: gemfiles/rails50.gemfile
33
+ - rvm: 2.1.8
34
+ gemfile: gemfiles/rails50.gemfile
35
+ allow_failures:
36
+ - rvm: ruby-head
37
+ - gemfile: gemfiles/rails50.gemfile
38
+ fast_finish: true
21
39
  notifications:
22
40
  emails:
23
41
  - tsukasa.oishi@gmail.com
42
+ bundler_args: --jobs 3 --retry 3
data/Appraisals CHANGED
@@ -1,15 +1,19 @@
1
- appraise "rails3" do
2
- gem "activerecord", "~> 3.2.0"
3
- end
4
-
5
1
  appraise "rails40" do
6
2
  gem "activerecord", "~> 4.0.0"
3
+ gem 'mysql2', '~> 0.3.10'
7
4
  end
8
5
 
9
6
  appraise "rails41" do
10
7
  gem "activerecord", "~> 4.1.0"
8
+ gem 'mysql2', '~> 0.3.13'
11
9
  end
12
10
 
13
11
  appraise "rails42" do
14
12
  gem "activerecord", "~> 4.2.0"
13
+ gem 'mysql2', '~> 0.3.13'
14
+ end
15
+
16
+ appraise "rails50" do
17
+ gem "activerecord", "5.0.0.beta3"
18
+ gem 'mysql2', '>= 0.3.18', '< 0.5'
15
19
  end
data/README.md CHANGED
@@ -1,10 +1,60 @@
1
1
  # EbisuConnection
2
-
3
2
  [![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)
4
3
 
5
- EbisuConnection supports to connect with Mysql slave servers. It doesn't need Load Balancer.
6
- You can assign a performance weight to each slave server. And slave config is reflected dynamic.
7
- EbisuConnection uses FreshConnection (https://github.com/tsukasaoishi/fresh_connection).
4
+ EbisuConnection allows access to slave servers.
5
+ You could assign a performance weight to each slave server.
6
+
7
+ ```
8
+ Rails ------------ Master DB
9
+ |
10
+ |
11
+ +---- Slave1 DB (weight 10)
12
+ |
13
+ |
14
+ +---- Slave2 DB (weight 20)
15
+ ```
16
+
17
+ If you could put a load balancer in front of slave servers, should use [FreshConnection](https://github.com/tsukasaoishi/fresh_connection).
18
+
19
+ ## Usage
20
+ ### Access to Slave
21
+ Read query goes to the slave server.
22
+
23
+ ```ruby
24
+ Article.where(:id => 1)
25
+ ```
26
+
27
+ ### Access to Master
28
+ If read query want to access to the master server, use `read_master`.
29
+ In before version 0.3.1, can use `readonly(false)`.
30
+
31
+ ```ruby
32
+ Article.where(:id => 1).read_master
33
+ ```
34
+
35
+ In transaction, All queries go to the master server.
36
+
37
+ ```ruby
38
+ Article.transaction do
39
+ Article.where(:id => 1)
40
+ end
41
+ ```
42
+
43
+ Create, Update and Delete queries go to the master server.
44
+
45
+ ```ruby
46
+ article = Article.create(...)
47
+ article.title = "FreshConnection"
48
+ article.save
49
+ article.destory
50
+ ```
51
+
52
+ ## Support Rails version
53
+ EbisuConnection supports Rails version 4.0 or later.
54
+ If you are using Rails 3.2, could use EbisuConnection version 1.0.0 or before.
55
+
56
+ ## Support DB
57
+ EbisuConnection supports MySQL and PostgreSQL.
8
58
 
9
59
  ## Installation
10
60
 
@@ -48,10 +98,10 @@ production:
48
98
  host: slave
49
99
  ```
50
100
 
51
- ```slave``` is base config to connect to slave servers.
52
- Others will use the master setting. If you want to change, write in the slave.
53
-
54
- Config of each slave server fill out config/slave.yaml
101
+ ```slave``` is a config to connect to slave servers.
102
+ Others will use the master server settings.
103
+
104
+ Config of each slave server fill out to `config/slave.yml`
55
105
 
56
106
  ```yaml
57
107
  production:
@@ -62,7 +112,7 @@ production:
62
112
  weight: 30
63
113
  ```
64
114
 
65
- config/slave.yaml is checked by end of action. If config changed, it's reflected dynamic. Application doesn't need restart.
115
+ If ``config/slave.yml`` changed, it is reflected dynamic. Application doesn't need restart.
66
116
 
67
117
  ```yaml
68
118
  "hostname, weight"
@@ -96,7 +146,7 @@ production:
96
146
  host: admin_slaves
97
147
  ```
98
148
 
99
- Config of each slave server fill out config/slave.yaml
149
+ Config of each slave server fill out to `config/slave.yml`
100
150
 
101
151
  ```yaml
102
152
  production:
@@ -111,7 +161,6 @@ production:
111
161
  - "slave4, 20"
112
162
  ```
113
163
 
114
-
115
164
  And call establish_fresh_connection method in model that access to ```admin_slave``` slave group.
116
165
 
117
166
  ```ruby
@@ -148,32 +197,6 @@ end
148
197
  If model that always access to master servers is exist, You may want to write ```master_db_only!``` in model.
149
198
  The model that master_db_only model's child is always access to master db.
150
199
 
151
- ## Usage
152
-
153
- Read query will be access to slave server.
154
-
155
- ```ruby
156
- Article.where(:id => 1)
157
- Article.count
158
- ```
159
-
160
- If you want to access to the master server, use read_master.
161
-
162
- ```ruby
163
- Article.where(:id => 1).read_master
164
- ```
165
-
166
- It is possible to use readonly(false) instead of read_master, but it will be depricated at future version.
167
-
168
- In transaction, Always will be access to master server.
169
-
170
- ```ruby
171
- Article.transaction do
172
- Article.where(:id => 1)
173
- end
174
- ```
175
-
176
-
177
200
  ### for Unicorn
178
201
 
179
202
  ```ruby
@@ -205,13 +228,12 @@ To run the test suite, you need mysql installed.
205
228
  How to setup your test environment.
206
229
 
207
230
  ```bash
208
- bundle install --path .bundle
209
- bundle exec appraisal install
231
+ ./bin/setup
210
232
  ```
211
233
 
212
234
  This command run the spec suite for all rails versions supported.
213
235
 
214
236
  ```base
215
- bundle exec appraisal rake test
237
+ ./bin/test
216
238
  ```
217
239
 
data/Rakefile CHANGED
@@ -1,10 +1,22 @@
1
1
  require "bundler/gem_tasks"
2
2
  require 'rake/testtask'
3
3
 
4
- Rake::TestTask.new do |t|
5
- t.libs.push "test"
6
- t.test_files = FileList['test/**/*_test.rb']
7
- t.verbose = true
4
+ desc 'Run mysql2 and postgresql test'
5
+ task :test do
6
+ Rake::Task["test:mysql2"].invoke
7
+ Rake::Task["test:postgresql"].invoke
8
+ end
9
+
10
+ namespace :test do
11
+ %w(mysql2 postgresql).each do |db|
12
+ Rake::TestTask.new(db) do |t|
13
+ t.libs << "test"
14
+ t.libs << "lib"
15
+ t.test_files = FileList["test/config/prepare_#{db}", 'test/**/*_test.rb']
16
+ t.verbose = false
17
+ t.warning = false
18
+ end
19
+ end
8
20
  end
9
21
 
10
22
  task :default => :test
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "ebisu_connection"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
data/bin/setup ADDED
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install --path .bundle
7
+ bundle exec appraisal install
8
+
9
+ # Do any other automated setup that you need to do here
data/bin/test ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle exec appraisal rake test
@@ -21,8 +21,11 @@ Gem::Specification.new do |spec|
21
21
 
22
22
  spec.required_ruby_version = '>= 2.0'
23
23
 
24
- spec.add_dependency 'fresh_connection', '~> 1.0.0'
24
+ spec.add_dependency 'fresh_connection', '~> 2.0.0'
25
+ spec.add_dependency 'concurrent-ruby', '~> 1.0.0'
25
26
 
27
+ spec.add_development_dependency 'mysql2', '>= 0.3.13', '< 0.5'
28
+ spec.add_development_dependency 'pg', '~> 0.11'
26
29
  spec.add_development_dependency "bundler", ">= 1.3.0", "< 2.0"
27
30
  spec.add_development_dependency "rake", ">= 0.8.7"
28
31
  spec.add_development_dependency 'appraisal'
@@ -3,5 +3,6 @@
3
3
  source "https://rubygems.org"
4
4
 
5
5
  gem "activerecord", "~> 4.0.0"
6
+ gem "mysql2", "~> 0.3.10"
6
7
 
7
8
  gemspec :path => "../"
@@ -3,5 +3,6 @@
3
3
  source "https://rubygems.org"
4
4
 
5
5
  gem "activerecord", "~> 4.1.0"
6
+ gem "mysql2", "~> 0.3.13"
6
7
 
7
8
  gemspec :path => "../"
@@ -3,5 +3,6 @@
3
3
  source "https://rubygems.org"
4
4
 
5
5
  gem "activerecord", "~> 4.2.0"
6
+ gem "mysql2", "~> 0.3.13"
6
7
 
7
8
  gemspec :path => "../"
@@ -0,0 +1,8 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "activerecord", "5.0.0.beta3"
6
+ gem "mysql2", ">= 0.3.18", "< 0.5"
7
+
8
+ gemspec :path => "../"
@@ -27,7 +27,10 @@ module EbisuConnection
27
27
  def slaves_file
28
28
  return @slaves_file if @slaves_file
29
29
  raise "nothing slaves_file. You have to set a file path using EbisuConnection.slaves_file= method" unless defined?(Rails)
30
- File.join(Rails.root, "config/slave.yaml")
30
+
31
+ @slaves_file = %w(yml yaml).map{|ext| Rails.root.join("config/slave.#{ext}").to_s }.detect {|f| File.exist?(f) }
32
+ raise "nothing slaves_file. You have to put a config/slave.yml file" unless @slaves_file
33
+ @slaves_file
31
34
  end
32
35
 
33
36
  def check_interval
@@ -1,13 +1,10 @@
1
- require 'fresh_connection/abstract_connection_manager'
2
- require 'ebisu_connection/conf_file'
3
- require 'ebisu_connection/slave_group'
4
- require 'active_support/deprecation'
1
+ require 'concurrent'
5
2
 
6
3
  module EbisuConnection
7
4
  class ConnectionManager < FreshConnection::AbstractConnectionManager
8
5
  def initialize(slave_group = "slave")
9
6
  super
10
- @slaves = {}
7
+ @slaves = Concurrent::Map.new
11
8
  end
12
9
 
13
10
  def slave_connection
@@ -23,59 +20,43 @@ module EbisuConnection
23
20
  end
24
21
  end
25
22
 
26
- def recovery(failure_connection, exception)
27
- if slave_down_message?(exception.message)
28
- slaves.remove_connection(failure_connection)
29
- true
30
- else
31
- false
32
- end
33
- end
34
-
35
23
  def clear_all_connections!
36
- synchronize do
37
- @slaves.values.each do |s|
38
- s.all_disconnect!
39
- end
40
-
41
- @slaves = {}
42
- ConfFile.conf_clear!
24
+ @slaves.each_value do |s|
25
+ s.all_disconnect!
43
26
  end
27
+
28
+ @slaves.clear
29
+ ConfFile.conf_clear!
44
30
  end
45
31
 
46
- def clear_all_connection!
47
- ActiveSupport::Deprecation.warn("clear_all_connection! has been deprecated. Use clear_all_connections! instead", caller)
48
- clear_all_connections!
32
+ def recovery?
33
+ slaves.recovery_connection?
49
34
  end
50
35
 
51
36
  private
52
37
 
53
38
  def check_own_connection
54
- synchronize do
55
- s = @slaves[current_thread_id]
39
+ s = @slaves[current_thread_id]
56
40
 
57
- if s && s.reserved_release?
58
- s.all_disconnect!
59
- @slaves.delete(current_thread_id)
60
- true
61
- else
62
- false
63
- end
41
+ if s && s.reserved_release?
42
+ s.all_disconnect!
43
+ @slaves.delete(current_thread_id)
44
+ true
45
+ else
46
+ false
64
47
  end
65
48
  end
66
49
 
67
50
  def reserve_release_all_connection
68
- synchronize do
69
- @slaves.values.each do |s|
70
- s.reserve_release_connection!
71
- end
72
- ConfFile.conf_clear!
51
+ @slaves.each_value do |s|
52
+ s.reserve_release_connection!
73
53
  end
54
+ ConfFile.conf_clear!
74
55
  end
75
56
 
76
57
  def slaves
77
- synchronize do
78
- @slaves[current_thread_id] ||= get_slaves
58
+ @slaves.fetch_or_store(current_thread_id) do |_|
59
+ get_slaves
79
60
  end
80
61
  end
81
62
 
@@ -86,5 +67,9 @@ module EbisuConnection
86
67
  def slaves_conf
87
68
  ConfFile.slaves_conf(slave_group)
88
69
  end
70
+
71
+ def current_thread_id
72
+ Thread.current.object_id
73
+ end
89
74
  end
90
75
  end
@@ -24,6 +24,10 @@ module EbisuConnection
24
24
  @connection ||= @connection_factory.new_connection
25
25
  end
26
26
 
27
+ def active?
28
+ connection.active?
29
+ end
30
+
27
31
  def disconnect!
28
32
  if @connection
29
33
  @connection.disconnect!
@@ -1,6 +1,3 @@
1
- require 'ebisu_connection/greatest_common_divisor'
2
- require 'ebisu_connection/slave'
3
-
4
1
  module EbisuConnection
5
2
  class SlaveGroup
6
3
  class AllSlavesHasGoneError < StandardError; end
@@ -18,13 +15,19 @@ module EbisuConnection
18
15
  @slaves[@roulette.sample]
19
16
  end
20
17
 
21
- def remove_connection(connection)
22
- return unless s = @slaves.detect{|s| s.connection == connection}
23
- s.disconnect! rescue nil
24
- @slaves.delete(s)
18
+ def recovery_connection?
19
+ dead_slaves = @slaves.select{|s| !s.active? }
20
+ return false if dead_slaves.empty?
21
+
22
+ dead_slaves.each do |s|
23
+ s.disconnect!
24
+ @slaves.delete(s)
25
+ end
26
+
25
27
  raise AllSlavesHasGoneError if @slaves.empty?
28
+
26
29
  recalc_roulette
27
- nil
30
+ true
28
31
  end
29
32
 
30
33
  def all_disconnect!
@@ -1,3 +1,3 @@
1
1
  module EbisuConnection
2
- VERSION = "1.0.0"
2
+ VERSION = "2.0.0"
3
3
  end
@@ -1,8 +1,12 @@
1
1
  require "fresh_connection"
2
- require 'ebisu_connection/conf_file'
3
- require 'ebisu_connection/connection_manager'
4
2
 
5
3
  module EbisuConnection
4
+ autoload :ConfFile, 'ebisu_connection/conf_file'
5
+ autoload :ConnectionManager, 'ebisu_connection/connection_manager'
6
+ autoload :SlaveGroup, 'ebisu_connection/slave_group'
7
+ autoload :Slave, 'ebisu_connection/slave'
8
+ autoload :GreatestCommonDivisor, 'ebisu_connection/greatest_common_divisor'
9
+
6
10
  class << self
7
11
  attr_writer :env
8
12
 
metadata CHANGED
@@ -1,17 +1,31 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ebisu_connection
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - tsukasaoishi
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2016-01-10 00:00:00.000000000 Z
11
+ date: 2016-03-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: fresh_connection
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 2.0.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 2.0.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: concurrent-ruby
15
29
  requirement: !ruby/object:Gem::Requirement
16
30
  requirements:
17
31
  - - "~>"
@@ -24,6 +38,40 @@ dependencies:
24
38
  - - "~>"
25
39
  - !ruby/object:Gem::Version
26
40
  version: 1.0.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: mysql2
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: 0.3.13
48
+ - - "<"
49
+ - !ruby/object:Gem::Version
50
+ version: '0.5'
51
+ type: :development
52
+ prerelease: false
53
+ version_requirements: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ version: 0.3.13
58
+ - - "<"
59
+ - !ruby/object:Gem::Version
60
+ version: '0.5'
61
+ - !ruby/object:Gem::Dependency
62
+ name: pg
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '0.11'
68
+ type: :development
69
+ prerelease: false
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '0.11'
27
75
  - !ruby/object:Gem::Dependency
28
76
  name: bundler
29
77
  requirement: !ruby/object:Gem::Requirement
@@ -116,11 +164,15 @@ files:
116
164
  - LICENSE.txt
117
165
  - README.md
118
166
  - Rakefile
167
+ - bin/console
168
+ - bin/setup
169
+ - bin/test
119
170
  - ebisu_connection.gemspec
120
171
  - gemfiles/rails3.gemfile
121
172
  - gemfiles/rails40.gemfile
122
173
  - gemfiles/rails41.gemfile
123
174
  - gemfiles/rails42.gemfile
175
+ - gemfiles/rails50.gemfile
124
176
  - lib/ebisu_connection.rb
125
177
  - lib/ebisu_connection/conf_file.rb
126
178
  - lib/ebisu_connection/connection_manager.rb