Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/eagletmt/switch_point
Switching database connection between readonly one and writable one
https://github.com/eagletmt/switch_point
Last synced: 6 days ago
JSON representation
Switching database connection between readonly one and writable one
- Host: GitHub
- URL: https://github.com/eagletmt/switch_point
- Owner: eagletmt
- License: mit
- Created: 2014-05-27T10:34:59.000Z (over 10 years ago)
- Default Branch: master
- Last Pushed: 2020-11-22T11:51:06.000Z (about 4 years ago)
- Last Synced: 2024-12-14T00:06:17.718Z (13 days ago)
- Language: Ruby
- Homepage: https://github.com/eagletmt/switch_point
- Size: 155 KB
- Stars: 592
- Watchers: 29
- Forks: 39
- Open Issues: 2
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE.txt
Awesome Lists containing this project
README
# SwitchPoint
[![Gem Version](https://badge.fury.io/rb/switch_point.svg)](http://badge.fury.io/rb/switch_point)
[![Build Status](https://travis-ci.org/eagletmt/switch_point.svg?branch=master)](https://travis-ci.org/eagletmt/switch_point)
[![Coverage Status](https://img.shields.io/coveralls/eagletmt/switch_point.svg?branch=master)](https://coveralls.io/r/eagletmt/switch_point?branch=master)
[![Code Climate](https://codeclimate.com/github/eagletmt/switch_point/badges/gpa.svg)](https://codeclimate.com/github/eagletmt/switch_point)Switching database connection between readonly one and writable one.
## Maintenance notice
switch_point won't support upcoming ActiveRecord v6.1 or later.
Developers should use the builtin multiple database feature introduced in ActiveRecord v6.0.
https://guides.rubyonrails.org/active_record_multiple_databases.html
Thus the supported ActiveRecord version is v3.2, v4.0, v4.1, v4.2, v5.0, v5.1, and v5.2.switch_point won't accept any new features. Bug fixes might be accepted.
If you'd like to add a new feature (and/or support ActiveRecord >= v6.1), feel free to fork switch_point gem.### Migration from switch_point to ActiveRecord multiple database feature
1. Upgrade your activerecord gem to v6.0
- ActiveRecord v6.0 is the only series which supports both builtin multiple database feature and switch_point.
2. Change your application to use ActiveRecord multiple database feature
- If you'd like to keep the number of connections during this step, it would require some tricks.
3. Remove switch_point gem from your Gemfile
4. Upgrade your activerecord gem to v6.1 or later## Installation
Add this line to your application's Gemfile:
gem 'switch_point'
And then execute:
$ bundle
Or install it yourself as:
$ gem install switch_point
## Usage
Suppose you have 4 databases: db-blog-master, db-blog-slave, db-comment-master and db-comment-slave.
Article model and Category model are stored in db-blog-{master,slave} and Comment model is stored in db-comment-{master,slave}.### Configuration
In database.yml:```yaml
production_blog_master:
adapter: mysql2
username: blog_writable
host: db-blog-master
production_blog_slave:
adapter: mysql2
username: blog_readonly
host: db-blog-slave
production_comment_master:
...
```In initializer:
```ruby
SwitchPoint.configure do |config|
config.define_switch_point :blog,
readonly: :"#{Rails.env}_blog_slave",
writable: :"#{Rails.env}_blog_master"
config.define_switch_point :comment,
readonly: :"#{Rails.env}_comment_slave",
writable: :"#{Rails.env}_comment_master"
end
```In models:
```ruby
class Article < ActiveRecord::Base
use_switch_point :blog
endclass Category < ActiveRecord::Base
use_switch_point :blog
endclass Comment < ActiveRecord::Base
use_switch_point :comment
end
```### Switching connections
```ruby
Article.with_readonly { Article.first } # Read from db-blog-slave
Category.with_readonly { Category.first } # Also read from db-blog-slave
Comment.with_readonly { Comment.first } # Read from db-comment-slaveArticle.with_readonly do
article = Article.first # Read from db-blog-slave
article.title = 'new title'
Article.with_writable do
article.save! # Write to db-blog-master
article.reload # Read from db-blog-master
Category.first # Read from db-blog-master
end
end
```Note that Article and Category shares their connections.
### Query cache
`Model.cache` and `Model.uncached` enables/disables query cache for both
readonly connection and writable connection.switch_point also provide a rack middleware `SwitchPoint::QueryCache` similar
to `ActiveRecord::QueryCache`. It enables query cache for all models using
switch_point.```ruby
# Replace ActiveRecord::QueryCache with SwitchPoint::QueryCache
config.middleware.swap ActiveRecord::QueryCache, SwitchPoint::QueryCache# Enable query cache for :nanika1 only.
config.middleware.swap ActiveRecord::QueryCache, SwitchPoint::QueryCache, [:nanika1]
```## Notes
### auto_writable
`auto_writable` is disabled by default.When `auto_writable` is enabled, destructive queries is sent to writable connection even in readonly mode.
But it does NOT work well on transactions.Suppose `after_save` callback is set to User model. When `User.create` is called, it proceeds as follows.
1. BEGIN TRANSACTION is sent to READONLY connection.
2. switch_point switches the connection to WRITABLE.
3. INSERT statement is sent to WRITABLE connection.
4. switch_point reset the connection to READONLY.
5. after_save callback is called.
- At this point, the connection is READONLY and in a transaction.
6. COMMIT TRANSACTION is sent to READONLY connection.### connection-related methods of model
Model has several connection-related methods: `connection_handler`, `connection_pool`, `connected?` and so on.
Since only `connection` method is monkey-patched, other connection-related methods doesn't work properly.
If you'd like to use those methods, send it to `Model.switch_point_proxy.model_for_connection`.## Internals
There's a proxy which holds two connections: readonly one and writable one.
A proxy has a thread-local state indicating the current mode: readonly or writable.Each ActiveRecord model refers to a proxy.
`ActiveRecord::Base.connection` is hooked and delegated to the referred proxy.When the writable connection is requested to execute destructive query, the readonly connection clears its query cache.
![switch_point](https://gyazo.wanko.cc/switch_point.svg)
### Special case: ActiveRecord::Base.connection
Basically, each connection managed by a proxy isn't shared between proxies.
But there's one exception: ActiveRecord::Base.If `:writable` key is omitted (e.g., Nanika1 model in spec/models), it uses `ActiveRecord::Base.connection` as writable one.
When `ActiveRecord::Base.connection` is requested to execute destructive query, all readonly connections managed by a proxy which uses `ActiveRecord::Base.connection` as a writable connection clear query cache.## Contributing
1. Fork it ( https://github.com/eagletmt/switch_point/fork )
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 a new Pull Request