{"id":13483802,"url":"https://github.com/kenn/standby","last_synced_at":"2025-12-24T09:57:27.281Z","repository":{"id":4728766,"uuid":"5877440","full_name":"kenn/standby","owner":"kenn","description":"Read from standby databases for ActiveRecord","archived":false,"fork":false,"pushed_at":"2023-11-04T09:45:54.000Z","size":87,"stargazers_count":87,"open_issues_count":4,"forks_count":25,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-03-02T15:15:50.846Z","etag":null,"topics":[],"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/kenn.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2012-09-19T20:12:17.000Z","updated_at":"2024-07-03T09:57:58.000Z","dependencies_parsed_at":"2024-01-05T21:59:00.490Z","dependency_job_id":null,"html_url":"https://github.com/kenn/standby","commit_stats":{"total_commits":73,"total_committers":14,"mean_commits":5.214285714285714,"dds":0.4657534246575342,"last_synced_commit":"babe13f028d45d76e815af17d2c2a91c6e4b9e5a"},"previous_names":["kenn/slavery"],"tags_count":16,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kenn%2Fstandby","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kenn%2Fstandby/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kenn%2Fstandby/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kenn%2Fstandby/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kenn","download_url":"https://codeload.github.com/kenn/standby/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245871682,"owners_count":20686246,"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":[],"created_at":"2024-07-31T17:01:15.424Z","updated_at":"2025-12-24T09:57:27.267Z","avatar_url":"https://github.com/kenn.png","language":"Ruby","readme":"# Standby - Read from standby databases for ActiveRecord (formerly Slavery)\n\n![Build Status](https://github.com/kenn/standby/actions/workflows/ci.yml/badge.svg)\n\nStandby is a simple, easy to use gem for ActiveRecord that enables conservative reading from standby databases, which means it won't automatically redirect all SELECTs to standbys.\n\nInstead, you can do `Standby.on_standby { User.count }` to send a particular query to a standby.\n\nBackground: Probably your app started off with one single database. As it grows, you would upgrade to a primary-standby (or master-slave) replication for redundancy. At this point, all queries still go to the primary and standbys are just backups. With that configuration, it's tempting to run some long-running queries on one of the standbys. And that's exactly what Standby does.\n\n* Conservative - Safe by default. Installing Standby won't change your app's current behavior.\n* Future proof - No dirty hacks. Simply works as a proxy for `ActiveRecord::Base.connection`.\n* Simple code - Intentionally small. You can read the entire source and completely stay in control.\n\nStandby works with ActiveRecord 3 or later.\n\n## Install\n\nAdd this line to your application's Gemfile:\n\n```ruby\ngem 'standby'\n```\n\nAnd create standby configs for each environment.\n\n```yaml\ndevelopment:\n  database: myapp_development\n\ndevelopment_standby:\n  database: myapp_development\n```\n\nBy convention, config keys with `[env]_standby` are automatically used for standby reads.\n\nNotice that we just copied the settings of `development` to `development_standby`. For `development` and `test`, it's actually recommended as probably you don't want to have replicating multiple databases on your machine. Two connections to the same identical database should be fine for testing purpose.\n\nIn case you prefer DRYer definition, YAML's aliasing and key merging might help.\n\n```yaml\ncommon: \u0026common\n  adapter: mysql2\n  username: root\n  database: myapp_development\n\ndevelopment:\n  \u003c\u003c: *common\n\ndevelopment_standby:\n  \u003c\u003c: *common\n```\n\nOptionally, you can use a database url for your connections:\n\n```yaml\ndevelopment: postgres://root:@localhost:5432/myapp_development\ndevelopment_standby: postgres://root:@localhost:5432/myapp_development_standby\n```\n\nAt this point, Standby does nothing. Run tests and confirm that nothing is broken.\n\n## Usage\n\nTo start using Standby, you need to add `Standby.on_standby` in your code. Queries in the `Standby.on_standby` block run on the standby.\n\n```ruby\nStandby.on_standby { User.count }   # =\u003e runs on standby\nStandby.on_standby(:two) { User.count }  # =\u003e runs on another standby configured as `development_standby_two`\n```\n\nYou can nest `on_standby` and `on_primary` interchangeably. The following code works as expected.\n\n```ruby\nStandby.on_standby do\n  ...\n  Standby.on_primary do\n    ...\n  end\n  ...\nend\n```\n\nAlternatively, you may call `on_standby` directly on the scope, so that the query will be read from standby when it's executed.\n\n```ruby\nUser.on_standby.where(active: true).count\n```\n\nCaveat: `pluck` is not supported by the scope syntax, you still need `Standby.on_standby` in this case.\n\n## Read-only user\n\nFor an extra safeguard, it is recommended to use a read-only user for standby access.\n\n```yaml\ndevelopment_standby:\n  \u003c\u003c: *common\n  username: readonly\n```\n\nWith MySQL, `GRANT SELECT` creates a read-only user.\n\n```SQL\nGRANT SELECT ON *.* TO 'readonly'@'localhost';\n```\n\nWith this user, writes on a standby should raise an exception.\n\n```ruby\nStandby.on_standby { User.create }  # =\u003e ActiveRecord::StatementInvalid: Mysql2::Error: INSERT command denied...\n```\n\nWith Postgres you can set the entire database to be readonly:\n\n```SQL\nALTER DATABASE myapp_development_standby SET default_transaction_read_only = true;\n```\n\nIt is a good idea to confirm this behavior in your test code as well.\n\n## Disable temporarily\n\nYou can quickly disable standby reads by dropping the following line in `config/initializers/standby.rb`.\n\n```ruby\nStandby.disabled = true\n```\n\nWith this line, Standby stops connection switching and all queries go to the primary.\n\nThis may be useful when one of the primary or the standby goes down. You would rewrite `database.yml` to make all queries go to the surviving database, until you restore or rebuild the failed one.\n\n## Transactional fixtures\n\nWhen `use_transactional_fixtures` is set to `true`, it's NOT recommended to\nwrite to the database besides fixtures, since the standby connection is not aware\nof changes performed in the primary connection due to [transaction isolation](https://en.wikipedia.org/wiki/Isolation_(database_systems)).\n\nIn that case, you are suggested to disable Standby in the test environment by\nputting the following in `test/test_helper.rb`\n(or `spec/spec_helper.rb` for RSpec users):\n\n```ruby\nStandby.disabled = true\n```\n\n## Upgrading from version 3 to version 4\n\nThe gem name has been changed from `slavery` to `standby`.\n\nUpdate your Gemfile\n\n```ruby\ngem 'standby'\n```\n\nThen\n\n* Replace `Slavery` with `Standby`, `on_slave` with `on_standby`, and `on_master` with `on_primary`\n* Update keys in `database.yml` (e.g. `development_slave` to `development_standby`)\n\n## Upgrading from version 2 to version 3\n\nPlease note that `Standby.spec_key=` method has been removed from version 3.\n\n## Support for non-Rails apps\n\nIf you're using ActiveRecord in a non-Rails app (e.g. Sinatra), be sure to set `RACK_ENV` environment variable in the boot sequence, then:\n\n```ruby\nrequire 'standby'\n\nActiveRecord::Base.configurations = {\n  'development' =\u003e          { adapter: 'mysql2', ... },\n  'development_standby' =\u003e  { adapter: 'mysql2', ... }\n}\nActiveRecord::Base.establish_connection(:development)\n```\n\n## Changelog\n\n* v4.0.0: Rename gem from Slavery to Standby\n* v3.0.0: Support for multiple standby targets ([@punchh](https://github.com/punchh))\n* v2.1.0: Debug log support / Database URL support / Rails 3.2 \u0026 4.0 compatibility (Thanks to [@citrus](https://github.com/citrus))\n* v2.0.0: Rails 5 support\n","funding_links":[],"categories":["Ruby","Database Tools"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkenn%2Fstandby","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkenn%2Fstandby","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkenn%2Fstandby/lists"}