switch_connection 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +26 -0
- data/.hound.yml +3 -0
- data/.rspec +2 -0
- data/.rubocop.yml +63 -0
- data/.rubocop_todo.yml +2 -0
- data/.ruby-version +1 -0
- data/.travis.yml +22 -0
- data/Appraisals +66 -0
- data/CHANGELOG.md +73 -0
- data/Gemfile +7 -0
- data/LICENSE.txt +22 -0
- data/README.md +143 -0
- data/Rakefile +16 -0
- data/assets/switch_point.svg +2 -0
- data/benchmark/proxy.rb +71 -0
- data/gemfiles/rails_3.2.gemfile +8 -0
- data/gemfiles/rails_4.0.gemfile +8 -0
- data/gemfiles/rails_4.1.gemfile +8 -0
- data/gemfiles/rails_4.2.gemfile +9 -0
- data/gemfiles/rails_5.0.gemfile +9 -0
- data/gemfiles/rails_5.1.gemfile +8 -0
- data/gemfiles/rails_5.2.gemfile +9 -0
- data/gemfiles/rails_edge.gemfile +9 -0
- data/lib/switch_connection.rb +66 -0
- data/lib/switch_connection/config.rb +94 -0
- data/lib/switch_connection/error.rb +12 -0
- data/lib/switch_connection/model.rb +144 -0
- data/lib/switch_connection/proxy.rb +165 -0
- data/lib/switch_connection/proxy_repository.rb +30 -0
- data/lib/switch_connection/version.rb +5 -0
- data/spec/models.rb +141 -0
- data/spec/spec_helper.rb +91 -0
- data/spec/switch_connection/model_spec.rb +402 -0
- data/spec/switch_connection_spec.rb +108 -0
- data/switch_connection.gemspec +36 -0
- metadata +265 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 3a610610ba7b802579bd70c8b25df8f8bba50299
|
4
|
+
data.tar.gz: c796e8855c8f3472629390723cd8c0c6c00559ea
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b3a4ad59a79b047914a09d125bae342993ab7b619cd48c23a2d7b0c53ade3be1d1d74948ae011a91741247b10729a611d5f1494e538945a641f196c9f4476958
|
7
|
+
data.tar.gz: 3d2fa748e38c0dc9536d9d41d0699868d387556df4d7730ba19e621a79a69e05d593f7b4810ed8e5f9d6dbdeb933fb4d4a0f765cb94b2025ceeaccc67543aca6
|
data/.gitignore
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
.bundle
|
4
|
+
.config
|
5
|
+
.yardoc
|
6
|
+
Gemfile.lock
|
7
|
+
InstalledFiles
|
8
|
+
_yardoc
|
9
|
+
coverage
|
10
|
+
doc/
|
11
|
+
lib/bundler/man
|
12
|
+
pkg
|
13
|
+
rdoc
|
14
|
+
spec/reports
|
15
|
+
test/tmp
|
16
|
+
test/version_tmp
|
17
|
+
tmp
|
18
|
+
*.bundle
|
19
|
+
*.so
|
20
|
+
*.o
|
21
|
+
*.a
|
22
|
+
mkmf.log
|
23
|
+
vendor
|
24
|
+
/gemfiles/*.lock
|
25
|
+
.idea
|
26
|
+
.ruby-version
|
data/.hound.yml
ADDED
data/.rspec
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
inherit_from: .rubocop_todo.yml
|
2
|
+
|
3
|
+
AllCops:
|
4
|
+
TargetRubyVersion: 2.3
|
5
|
+
DisplayCopNames: true
|
6
|
+
Exclude:
|
7
|
+
- "gemfiles/**/*"
|
8
|
+
- "vendor/**/*"
|
9
|
+
|
10
|
+
Performance/RedundantBlockCall:
|
11
|
+
Enabled: false
|
12
|
+
|
13
|
+
Layout/AlignParameters:
|
14
|
+
Enabled: false
|
15
|
+
|
16
|
+
LineLength:
|
17
|
+
Max: 100
|
18
|
+
|
19
|
+
Metrics:
|
20
|
+
Enabled: false
|
21
|
+
|
22
|
+
Naming/FileName:
|
23
|
+
Exclude:
|
24
|
+
- Appraisals
|
25
|
+
|
26
|
+
Metrics/BlockLength:
|
27
|
+
Exclude:
|
28
|
+
- 'spec/**/*'
|
29
|
+
|
30
|
+
Style/AccessModifierDeclarations:
|
31
|
+
Enabled: false
|
32
|
+
Style/Alias:
|
33
|
+
EnforcedStyle: prefer_alias_method
|
34
|
+
Style/BlockDelimiters:
|
35
|
+
Enabled: false
|
36
|
+
Style/GuardClause:
|
37
|
+
Enabled: false
|
38
|
+
Style/HashSyntax:
|
39
|
+
Exclude:
|
40
|
+
- Rakefile
|
41
|
+
Style/IfUnlessModifier:
|
42
|
+
Enabled: false
|
43
|
+
Style/Lambda:
|
44
|
+
Enabled: false
|
45
|
+
Style/Next:
|
46
|
+
Enabled: false
|
47
|
+
Style/PercentLiteralDelimiters:
|
48
|
+
PreferredDelimiters:
|
49
|
+
'%w': '[]'
|
50
|
+
Style/RaiseArgs:
|
51
|
+
EnforcedStyle: compact
|
52
|
+
Style/SignalException:
|
53
|
+
Enabled: false
|
54
|
+
Style/TrailingCommaInArguments:
|
55
|
+
Enabled: false
|
56
|
+
Style/TrailingCommaInArrayLiteral:
|
57
|
+
Enabled: false
|
58
|
+
Style/TrailingCommaInHashLiteral:
|
59
|
+
Enabled: false
|
60
|
+
Style/FrozenStringLiteralComment:
|
61
|
+
Exclude:
|
62
|
+
- "gemfiles/*.gemfile"
|
63
|
+
- "Appraisals"
|
data/.rubocop_todo.yml
ADDED
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.3.6
|
data/.travis.yml
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
language: ruby
|
2
|
+
rvm:
|
3
|
+
- 2.3.7
|
4
|
+
- 2.4.4
|
5
|
+
- 2.5.1
|
6
|
+
- ruby-head
|
7
|
+
gemfile:
|
8
|
+
- gemfiles/rails_3.2.gemfile
|
9
|
+
- gemfiles/rails_4.0.gemfile
|
10
|
+
- gemfiles/rails_4.1.gemfile
|
11
|
+
- gemfiles/rails_4.2.gemfile
|
12
|
+
- gemfiles/rails_5.0.gemfile
|
13
|
+
- gemfiles/rails_5.1.gemfile
|
14
|
+
- gemfiles/rails_5.2.gemfile
|
15
|
+
- gemfiles/rails_edge.gemfile
|
16
|
+
sudo: false
|
17
|
+
after_script:
|
18
|
+
- bundle exec rake benchmark
|
19
|
+
matrix:
|
20
|
+
allow_failures:
|
21
|
+
- rvm: ruby-head
|
22
|
+
- gemfile: gemfiles/rails_edge.gemfile
|
data/Appraisals
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
appraise 'rails-3.2' do
|
2
|
+
gem 'activerecord', '~> 3.2.0'
|
3
|
+
|
4
|
+
platforms :ruby do
|
5
|
+
gem 'sqlite3'
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
appraise 'rails-4.0' do
|
10
|
+
gem 'activerecord', '~> 4.0.0'
|
11
|
+
|
12
|
+
platforms :ruby do
|
13
|
+
gem 'sqlite3'
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
appraise 'rails-4.1' do
|
18
|
+
gem 'activerecord', '~> 4.1.0'
|
19
|
+
|
20
|
+
platforms :ruby do
|
21
|
+
gem 'sqlite3'
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
appraise 'rails-4.2' do
|
26
|
+
gem 'activerecord', '~> 4.2.0'
|
27
|
+
|
28
|
+
platforms :ruby do
|
29
|
+
gem 'sqlite3'
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
appraise 'rails-5.0' do
|
34
|
+
gem 'activerecord', '~> 5.0.0'
|
35
|
+
|
36
|
+
platforms :ruby do
|
37
|
+
gem 'sqlite3'
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
appraise 'rails-5.1' do
|
42
|
+
gem 'activerecord', '~> 5.1.0'
|
43
|
+
|
44
|
+
platforms :ruby do
|
45
|
+
gem 'sqlite3'
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
appraise 'rails-5.2' do
|
50
|
+
gem 'activerecord', '~> 5.2.0'
|
51
|
+
|
52
|
+
platforms :ruby do
|
53
|
+
gem 'sqlite3'
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
appraise 'rails-edge' do
|
58
|
+
gem 'activerecord', git: 'https://github.com/rails/rails'
|
59
|
+
gem 'arel', git: 'https://github.com/rails/arel'
|
60
|
+
|
61
|
+
platforms :ruby do
|
62
|
+
gem 'sqlite3'
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# vim: set ft=ruby:
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
## 1.0.0 (2019-07-31)
|
2
|
+
- Multi slaves support
|
3
|
+
- Connect to master by default
|
4
|
+
- Change switch point (thread safe)
|
5
|
+
- Log connection name
|
6
|
+
|
7
|
+
## 0.8.0 (2016-06-06)
|
8
|
+
- Drop Ruby 2.0.0 and 2.1 support
|
9
|
+
- Add `AR::Base#with_readonly` and `AR::Base#with_writable`
|
10
|
+
- short-hand for `AR::Base.with_readonly` and `AR::Base.with_writable`
|
11
|
+
- Add `AR::Base#transaction_with`
|
12
|
+
- short-hand for `AR::Base.transaction_with`
|
13
|
+
- Fix warnings for Rails 5.0
|
14
|
+
|
15
|
+
## 0.7.0 (2015-10-16)
|
16
|
+
- `Model.with_readonly` and `Model.with_writable` now raises error when the Model doesn't use switch_point
|
17
|
+
|
18
|
+
## 0.6.0 (2015-04-14)
|
19
|
+
- Add `SwitchConnection::QueryCache` middleware
|
20
|
+
- `Model.cache` and `Model.uncached` is now hooked by switch_point
|
21
|
+
- `Model.cache` enables query cache for both readonly and writable.
|
22
|
+
- `Model.uncached` disables query cache for both readonly and writable.
|
23
|
+
- Add `SwitchConnection.with_readonly_all` and `SwitchConnection.with_writable_all` as shorthand
|
24
|
+
|
25
|
+
## 0.5.0 (2014-11-05)
|
26
|
+
- Rename `SwitchConnection.with_connection` to `SwitchConnection.with_mode`
|
27
|
+
- To avoid confusion with `ActiveRecord::ConnectionPool#with_connection`
|
28
|
+
- Inherit superclass' switch_point configuration
|
29
|
+
|
30
|
+
## 0.4.4 (2014-07-14)
|
31
|
+
- Memorize switch_point config to ConnectionSpecification#config instead of ConnectionPool
|
32
|
+
- To support multi-threaded environment since Rails 4.0.
|
33
|
+
|
34
|
+
## 0.4.3 (2014-06-24)
|
35
|
+
- Add Model.transaction_with method (#2, @ryopeko)
|
36
|
+
|
37
|
+
## 0.4.2 (2014-06-19)
|
38
|
+
- Establish connection lazily
|
39
|
+
- Just like ActiveRecord::Base, real connection isn't created until `.connection` is called
|
40
|
+
|
41
|
+
## 0.4.1 (2014-06-19)
|
42
|
+
- Support :writable only configuration
|
43
|
+
|
44
|
+
## 0.4.0 (2014-06-17)
|
45
|
+
- auto_writable is disabled by default
|
46
|
+
- To restore the previous behavior, set `config.auto_writable = true`.
|
47
|
+
- Add shorthand methods `SwitchConnection.with_readonly`, `SwitchConnection.with_writable`
|
48
|
+
|
49
|
+
## 0.3.1 (2014-06-04)
|
50
|
+
- Support defaulting to writable ActiveRecord::Base connection
|
51
|
+
- When `:writable` key is omitted, ActiveRecord::Base is used for the writable connection.
|
52
|
+
|
53
|
+
## 0.3.0 (2014-06-04)
|
54
|
+
- Improve thread safety
|
55
|
+
- Raise appropriate error if unknown mode is given to with_connection
|
56
|
+
|
57
|
+
## 0.2.3 (2014-06-02)
|
58
|
+
- Support specifying the same database name within different switch_point
|
59
|
+
- Add Proxy#readonly? and Proxy#writable? predicate
|
60
|
+
|
61
|
+
## 0.2.2 (2014-05-30)
|
62
|
+
- Fix nil error on with_{readonly,writable} from non-switch_point model
|
63
|
+
|
64
|
+
## 0.2.1 (2014-05-29)
|
65
|
+
- Add Proxy#switch_name to switch proxy configuration
|
66
|
+
- Fix weird nil error when Config#define_switch_point isn't called yet
|
67
|
+
|
68
|
+
## 0.2.0 (2014-05-29)
|
69
|
+
- Always send destructive operations to writable connection
|
70
|
+
- Fix bug on pooled connections
|
71
|
+
|
72
|
+
## 0.1.0 (2014-05-28)
|
73
|
+
- Initial release
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Kohei Suzuki
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,143 @@
|
|
1
|
+
# SwitchConnection
|
2
|
+
[](http://badge.fury.io/rb/switch_point)
|
3
|
+
[](https://travis-ci.org/phamvannhung22123/switch_point)
|
4
|
+
[](https://coveralls.io/r/phamvannhung2e123/switch_point?branch=master)
|
5
|
+
[](https://codeclimate.com/github/phamvannhung2e123/switch_point)
|
6
|
+
|
7
|
+
Switching database connection between slave one and writable one. Fork from `switch_point` gem.
|
8
|
+
Original Version: https://github.com/eagletmt/switch_point.
|
9
|
+
|
10
|
+
## Installation
|
11
|
+
|
12
|
+
Add this line to your application's Gemfile:
|
13
|
+
|
14
|
+
gem 'switch_connection'
|
15
|
+
|
16
|
+
And then execute:
|
17
|
+
|
18
|
+
$ bundle
|
19
|
+
|
20
|
+
Or install it yourself as:
|
21
|
+
|
22
|
+
$ gem install switch_connection
|
23
|
+
|
24
|
+
## Usage
|
25
|
+
Suppose you have 4 databases: db-blog-master, db-blog-slave, db-comment-master and db-comment-slave.
|
26
|
+
Article model and Category model are stored in db-blog-{master,slave} and Comment model is stored in db-comment-{master,slave}.
|
27
|
+
|
28
|
+
### Configuration
|
29
|
+
In database.yml:
|
30
|
+
|
31
|
+
```yaml
|
32
|
+
production_blog_master:
|
33
|
+
adapter: mysql2
|
34
|
+
username: blog_writable
|
35
|
+
host: db-blog-master
|
36
|
+
production_blog_slave:
|
37
|
+
adapter: mysql2
|
38
|
+
username: blog_slave
|
39
|
+
host: db-blog-slave
|
40
|
+
production_comment_master:
|
41
|
+
...
|
42
|
+
```
|
43
|
+
|
44
|
+
In initializer:
|
45
|
+
|
46
|
+
```ruby
|
47
|
+
SwitchConnection.configure do |config|
|
48
|
+
config.define_switch_point :blog,
|
49
|
+
slaves: [:"#{Rails.env}_blog_slave1",:"#{Rails.env}_blog_slave2"]
|
50
|
+
master: :"#{Rails.env}_blog_master"
|
51
|
+
config.define_switch_point :comment,
|
52
|
+
slaves: [:"#{Rails.env}_comment_slave"]
|
53
|
+
master: :"#{Rails.env}_comment_master"
|
54
|
+
end
|
55
|
+
```
|
56
|
+
|
57
|
+
In models:
|
58
|
+
|
59
|
+
```ruby
|
60
|
+
class Article < ActiveRecord::Base
|
61
|
+
use_switch_point :blog
|
62
|
+
end
|
63
|
+
|
64
|
+
class Category < ActiveRecord::Base
|
65
|
+
use_switch_point :blog
|
66
|
+
end
|
67
|
+
|
68
|
+
class Comment < ActiveRecord::Base
|
69
|
+
use_switch_point :comment
|
70
|
+
end
|
71
|
+
```
|
72
|
+
|
73
|
+
### Switching connections
|
74
|
+
|
75
|
+
```ruby
|
76
|
+
Article.with_slave { Article.first } # Read from db-blog-slave
|
77
|
+
Category.with_slave { Category.first } # Also read from db-blog-slave
|
78
|
+
Comment.with_slave { Comment.first } # Read from db-comment-slave
|
79
|
+
|
80
|
+
Article.with_slave do
|
81
|
+
article = Article.first # Read from db-blog-slave
|
82
|
+
article.title = 'new title'
|
83
|
+
Article.with_master do
|
84
|
+
article.save! # Write to db-blog-master
|
85
|
+
article.reload # Read from db-blog-master
|
86
|
+
Category.first # Read from db-blog-master
|
87
|
+
end
|
88
|
+
end
|
89
|
+
```
|
90
|
+
|
91
|
+
- with_switch_point
|
92
|
+
```ruby
|
93
|
+
Book.with_switch_point(:main) { Book.count }
|
94
|
+
```
|
95
|
+
|
96
|
+
Note that Article and Category shares their connections.
|
97
|
+
|
98
|
+
## Notes
|
99
|
+
|
100
|
+
### auto_master
|
101
|
+
`auto_master` by default.
|
102
|
+
|
103
|
+
When `auto_master` is enabled, destructive queries is sent to writable connection even in slave mode.
|
104
|
+
But it does NOT work well on transactions.
|
105
|
+
|
106
|
+
Suppose `after_save` callback is set to User model. When `User.create` is called, it proceeds as follows.
|
107
|
+
|
108
|
+
1. BEGIN TRANSACTION is sent to READONLY connection.
|
109
|
+
2. switch_point switches the connection to WRITABLE.
|
110
|
+
3. INSERT statement is sent to WRITABLE connection.
|
111
|
+
4. switch_point reset the connection to READONLY.
|
112
|
+
5. after_save callback is called.
|
113
|
+
- At this point, the connection is READONLY and in a transaction.
|
114
|
+
6. COMMIT TRANSACTION is sent to READONLY connection.
|
115
|
+
|
116
|
+
### connection-related methods of model
|
117
|
+
Model has several connection-related methods: `connection_handler`, `connection_pool`, `connected?` and so on.
|
118
|
+
Since only `connection` method is monkey-patched, other connection-related methods doesn't work properly.
|
119
|
+
If you'd like to use those methods, send it to `Model.switch_point_proxy.model_for_connection`.
|
120
|
+
|
121
|
+
## Internals
|
122
|
+
There's a proxy which holds two connections: slave one and writable one.
|
123
|
+
A proxy has a thread-local state indicating the current mode: slave or writable.
|
124
|
+
|
125
|
+
Each ActiveRecord model refers to a proxy.
|
126
|
+
`ActiveRecord::Base.connection` is hooked and delegated to the referred proxy.
|
127
|
+
|
128
|
+
When the writable connection is requested to execute destructive query, the slave connection clears its query cache.
|
129
|
+
|
130
|
+

|
131
|
+
|
132
|
+
### Special case: ActiveRecord::Base.connection
|
133
|
+
Basically, each connection managed by a proxy isn't shared between proxies.
|
134
|
+
But there's one exception: ActiveRecord::Base.
|
135
|
+
|
136
|
+
|
137
|
+
## Contributing
|
138
|
+
|
139
|
+
1. Fork it ( https://github.com/phamvanmhung2e123/switch_point/fork )
|
140
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
141
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
142
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
143
|
+
5. Create a new Pull Request
|