{"id":15490796,"url":"https://github.com/tsukasaoishi/fresh_connection","last_synced_at":"2025-04-06T18:16:09.486Z","repository":{"id":45322213,"uuid":"2585294","full_name":"tsukasaoishi/fresh_connection","owner":"tsukasaoishi","description":"FreshConnection provides access to one or more configured database replicas.","archived":false,"fork":false,"pushed_at":"2024-08-15T07:45:09.000Z","size":275,"stargazers_count":58,"open_issues_count":6,"forks_count":12,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-03-13T07:01:55.578Z","etag":null,"topics":["activerecord","rails","replica","ruby"],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tsukasaoishi.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2011-10-16T08:26:42.000Z","updated_at":"2024-08-15T07:44:47.000Z","dependencies_parsed_at":"2024-06-20T21:48:49.717Z","dependency_job_id":"dea8f38d-ba12-4733-839c-fb76f6adf7f5","html_url":"https://github.com/tsukasaoishi/fresh_connection","commit_stats":{"total_commits":312,"total_committers":3,"mean_commits":104.0,"dds":0.07051282051282048,"last_synced_commit":"0c11f613a143fcf6047f2dde189fffa8a289323e"},"previous_names":[],"tags_count":50,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tsukasaoishi%2Ffresh_connection","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tsukasaoishi%2Ffresh_connection/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tsukasaoishi%2Ffresh_connection/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tsukasaoishi%2Ffresh_connection/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tsukasaoishi","download_url":"https://codeload.github.com/tsukasaoishi/fresh_connection/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247526764,"owners_count":20953143,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["activerecord","rails","replica","ruby"],"created_at":"2024-10-02T07:38:00.161Z","updated_at":"2025-04-06T18:16:09.451Z","avatar_url":"https://github.com/tsukasaoishi.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"# FreshConnection\n[![Gem Version](https://badge.fury.io/rb/fresh_connection.svg)](http://badge.fury.io/rb/fresh_connection) [![Build Status](https://travis-ci.org/tsukasaoishi/fresh_connection.svg?branch=master)](https://travis-ci.org/tsukasaoishi/fresh_connection) [![Code Climate](https://codeclimate.com/github/tsukasaoishi/fresh_connection/badges/gpa.svg)](https://codeclimate.com/github/tsukasaoishi/fresh_connection)\n\n**FreshConnection** provides access to one or more configured database replicas.\n\nFor example:\n\n```text\nRails ------------ DB Master\n             |\n             +---- DB Replica\n```\n\nor\n\n```text\nRails -------+---- DB Master\n             |\n             |                     +------ DB Replica1\n             |                     |\n             +---- Loadbalancer ---+\n                                   |\n                                   +------ DB Replica2\n```\n\nFreshConnction connects one or more configured DB replicas, or with multiple replicas behind a DB query load balancer.\n\n- Read queries go to the DB replica.\n- Write queries go to the DB master.\n- Within a transaction, all queries go to the DB master.\n\n### Failover\nFreshConnection assumes that there is a load balancer in front of multi replica servers.  \nWhen what happens one of the replicas is unreachable for any reason, FreshConnection will try three retries to access to a replica via a load balancer.  \n\nRemoving a trouble replica from a cluster is a work of the load balancer.  \nFreshConnection expects the load balancer to work during three retries.  \n\nIf you would like access to multi replica servers without a load balancer, you should use [EbisuConnection](https://github.com/tsukasaoishi/ebisu_connection).  \nEbisuConnection has functions of load balancer.\n\n## Usage\n### Access to the DB Replica\nRead queries are automatically connected to the DB replica.\n\n```ruby\nArticle.where(id: 1)\n\nAccount.count\n```\n\n### Access to the DB Master\nIf you wish to ensure that queries are directed to the DB master, call `read_master`.\n\n```ruby\nArticle.where(id: 1).read_master\n\nAccount.read_master.count\n```\n\nWithin transactions, all queries are connected to the DB master.\n\n```ruby\nArticle.transaction do\n  Article.where(id: 1)\nend\n```\n\nCreate, update and delete queries are connected to the DB master.\n\n```ruby\nnew_article = Article.create(...)\nnew_article.title = \"FreshConnection\"\nnew_article.save\n...\nold_article.destroy\n```\n\n## ActiveRecord Versions Supported\n\n- FreshConnection supports ActiveRecord version 5.2 or later.\n- If you are using Rails 5.1, you can use FreshConnection version 3.0.3 or before.\n\n### Not Support Multiple Database\nI haven't tested it in an environment using MultipleDB in Rails 6.\nI plan to enable use with MultipleDB in FreshConnection version 4.0 or later.\n\n## Databases Supported\nFreshConnection currently supports MySQL and PostgreSQL.\n\n## Installation\nAdd this line to your application's `Gemfile`:\n\n```ruby\ngem \"fresh_connection\"\n```\n\nAnd then execute:\n\n```\n$ bundle\n```\n\nOr install it manually with:\n\n```\n$ gem install fresh_connection\n```\n\n## Configuration\n\nThe FreshConnection database replica is configured within the standard Rails\ndatabase configuration file, `config/database.yml`, using a `replica:` stanza.\n\nBelow is a sample such configuration file.\n\n### `config/database.yml`\n\n```yaml\ndefault: \u0026default\n  adapter: mysql2\n  encoding: utf8\n  pool: \u003c%%= ENV.fetch(\"RAILS_MAX_THREADS\") { 5 } %\u003e\n  username: root\n  password:\n\nproduction:\n  \u003c\u003c: *default\n  database: blog_production\n  username: master_db_user\n  password: \u003c%= ENV['MASTER_DATABASE_PASSWORD'] %\u003e\n  host: master_db\n\n  replica:\n    username: replica_db_user\n    password: \u003c%= ENV['REPLICA_DATABASE_PASSWORD'] %\u003e\n    host: replica_db\n```\n\n`replica` is the configuration used for connecting read-only queries to the database replica.  All other connections will use the database master settings.\n\n**NOTE:** \nThe 'replica' stanza has a special meaning in Rails6.  \nIn Rails6, use a name other than 'replica', and specify that name using establish_fresh_connection in ApplicationRecord etc.\n\n### Multiple DB Replicas\nIf you want to use multiple configured DB replicas, the configuration can contain multiple `replica` stanzas in the configuration file `config/database.yml`.\n\nFor example:\n\n```yaml\ndefault: \u0026default\n  adapter: mysql2\n  encoding: utf8\n  pool: \u003c%%= ENV.fetch(\"RAILS_MAX_THREADS\") { 5 } %\u003e\n  username: root\n  password:\n\nproduction:\n  \u003c\u003c: *default\n  database: blog_production\n  username: master_db_user\n  password: \u003c%= ENV['MASTER_DATABASE_PASSWORD'] %\u003e\n  host: master_db\n\n  replica:\n    username: replica_db_user\n    password: \u003c%= ENV['REPLICA_DATABASE_PASSWORD'] %\u003e\n    host: replica_db\n\n  admin_replica:\n    username: admin_replica_db_user\n    password: \u003c%= ENV['ADMIN_REPLICA_DATABASE_PASSWORD'] %\u003e\n    host: admin_replica_db\n```\n\nThe custom replica stanza can then be applied as an argument to the `establish_fresh_connection` method in the models that should use it.  For example:\n\n```ruby\nclass AdminUser \u003c ActiveRecord::Base\n  establish_fresh_connection :admin_replica\nend\n```\n\nThe child (sub) classes of the configured model will inherit the same access as the parent class.  Example:\n\n```ruby\nclass AdminBase \u003c ActiveRecord::Base\n  establish_fresh_connection :admin_replica\nend\n\nclass AdminUser \u003c AdminBase\nend\n\nclass Benefit \u003c AdminBase\nend\n\nclass Customer \u003c ActiveRecord::Base\nend\n```\n\nThe `AdminUser` and `Benefit` models will access the database configured for the `admin_replica` group.\n\nThe `Customer` model will use the default connections: read-only queries will connect to the standard DB replica, and state-changing queries will connect to the DB master.\n\n\n### Replica Configuration With Environment Variables\n\nAlternative to using a configuration in the `database.yml` file, it is possible to completely specify the replica access components using environment variables.\n\nThe environment variables corresponding to the `:replica` group are `DATABASE_REPLICA_URL`.  \nThe URL string components is the same as Rails' `DATABASE_URL'.\n\n#### Multiple Replica Environment Variables\n\nTo specific URLs for multiple replicas, replace the string `REPLICA` in the environment variable name with the replica name, in upper case. See the examples for replicas: `:replica1`, `:replica2`, and `:admin_replica`\n\n\n    DATABASE_REPLICA1_URL='mysql://localhost/dbreplica1?pool=5\u0026reconnect=true'\n    DATABASE_REPLICA2_URL='postgresql://localhost:6432/ro_db?pool=5\u0026reconnect=true'\n    DATABASE_ADMIN_REPLICA_URL='postgresql://localhost:6432/admin_db?pool=5\u0026reconnect=true'\n\n\n### Master-only Models\n\nIt is possible to declare that specific models always use the DB master for all connections, using the `master_db_only!` method:\n\n```ruby\nclass CustomerState \u003c ActiveRecord::Base\n  master_db_only!\nend\n```\n\nAll queries generated by methods on the `CustomerState` model will be directed to the DB master.\n\n### Using FreshConnection With Unicorn\n\nWhen using FreshConnection with Unicorn (or any other multi-processing web server which restarts processes on the fly), connection management needs special attention during startup:\n\n```ruby\nbefore_fork do |server, worker|\n  ...\n  ActiveRecord::Base.clear_all_replica_connections!\n  ...\nend\n```\n\n### Replica Connection Manager\nThe default replica connection manager is `FreshConnection::ConnectionManager`. If an alternative (custom) replica connection manager is desired, this can be done with a simple assignment within a Rails initializer:\n\n`config/initializers/fresh_connection.rb`:\n\n```ruby\nFreshConnection.connection_manager = MyOwnReplicaConnection\n```\n\nThe `MyOwnReplicaConnection` class should inherit from `FreshConnection::AbstractConnectionManager`, which has this interface:\n\n```ruby\nclass MyOwnReplicaConnection \u003c FreshConnection::AbstractConnectionManager\n\n  def replica_connection\n    # must return an instance of a subclass of ActiveRecord::ConnectionAdapters\n    # eg: ActiveRecord::ConnectionAdapter::Mysql2Adapter\n    # or: ActiveRecord::ConnectionAdapter::PostgresqlAdapter\n  end\n\n  def clear_all_connections!\n    # called to disconnect all connections\n  end\n\n  def put_aside!\n    # called when end of Rails controller action\n  end\n\n  def recovery?\n    # called when raising exceptions on access to the DB replica\n    # access will be retried when this method returns true\n  end\n\nend\n```\n\n\n## Contributing\n\n1. Fork it\n2. Create your feature branch (`git checkout -b my-new-feature`)\n3. Commit your changes (`git commit -am 'Add some feature'`)\n4. Push to the branch (`git push origin my-new-feature`)\n5. Create new Pull Request\n\n## Test\n\nI'm glad that you would like to test!\nTo run the test suite, both `mysql` and `postgresql` must be installed.\n\n### Test Configuration\n\nFirst, configure the test servers in `test/config/*.yml`\n\nThen, run:\n\n```bash\n./bin/setup\n```\n\n### Running Tests\n\nTo run the spec suite for all supported versions of rails:\n\n```bash\n./bin/test\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftsukasaoishi%2Ffresh_connection","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftsukasaoishi%2Ffresh_connection","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftsukasaoishi%2Ffresh_connection/lists"}