slavery 3.0.0 → 4.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 +5 -5
- data/.gitignore +2 -2
- data/.travis.yml +10 -9
- data/Gemfile +1 -1
- data/README.md +63 -40
- data/Rakefile +9 -1
- data/gemfiles/rails3.2.gemfile +1 -1
- data/gemfiles/rails4.2.gemfile +1 -1
- data/gemfiles/rails5.2.gemfile +5 -0
- data/lib/standby.rb +29 -0
- data/lib/standby/active_record/base.rb +25 -0
- data/lib/{slavery → standby}/active_record/connection_handling.rb +0 -0
- data/lib/standby/active_record/log_subscriber.rb +12 -0
- data/lib/standby/active_record/relation.rb +28 -0
- data/lib/standby/base.rb +40 -0
- data/lib/{slavery → standby}/connection_holder.rb +5 -5
- data/lib/{slavery → standby}/error.rb +1 -1
- data/lib/{slavery → standby}/transaction.rb +1 -1
- data/lib/standby/version.rb +3 -0
- data/slavery.gemspec +6 -3
- data/spec/active_record/log_subscriber_spec.rb +10 -10
- data/spec/configuration_spec.rb +12 -12
- data/spec/slavery_spec.rb +40 -40
- data/spec/spec_helper.rb +10 -10
- data/standby.gemspec +24 -0
- metadata +18 -17
- data/gemfiles/rails4.gemfile +0 -5
- data/lib/slavery.rb +0 -29
- data/lib/slavery/active_record/base.rb +0 -25
- data/lib/slavery/active_record/log_subscriber.rb +0 -12
- data/lib/slavery/active_record/relation.rb +0 -28
- data/lib/slavery/base.rb +0 -40
- data/lib/slavery/version.rb +0 -3
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 | 
            -
             | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 2 | 
            +
            SHA256:
         | 
| 3 | 
            +
              metadata.gz: f8332b57194b74343f78c15ecdebeb7e095399c83cd881d000e3f27006fbcd81
         | 
| 4 | 
            +
              data.tar.gz: 2ce524c9a34355b9720d1d8fb428ae2715d2be8117d5c6c9327ac2c67c4c280f
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 25c186e7781354125ba4e8c141ffbc74820b11cc5da69cd83ba1e8aa80dd472575ba9646ce7cd9107f823cebd6d252bffebcb7bf95ba4520602da5383d3109f3
         | 
| 7 | 
            +
              data.tar.gz: 02e38582bd24b63dbeada69fc22b3567539ad90c48841bdf2f1c0ed00812f97a6ae73aae58fb9ad9a00d0e974216851e59f60085743005d1ffe06362acf7c570
         | 
    
        data/.gitignore
    CHANGED
    
    
    
        data/.travis.yml
    CHANGED
    
    | @@ -1,13 +1,14 @@ | |
| 1 1 | 
             
            language: ruby
         | 
| 2 2 |  | 
| 3 | 
            -
             | 
| 4 | 
            -
             | 
| 5 | 
            -
             - | 
| 6 | 
            -
             | 
| 7 | 
            -
             | 
| 8 | 
            -
             | 
| 9 | 
            -
              -  | 
| 10 | 
            -
             | 
| 11 | 
            -
              -  | 
| 3 | 
            +
            matrix:
         | 
| 4 | 
            +
              include:
         | 
| 5 | 
            +
              - rvm: ruby-head
         | 
| 6 | 
            +
                gemfile: Gemfile
         | 
| 7 | 
            +
              - rvm: 2.5
         | 
| 8 | 
            +
                gemfile: gemfiles/rails5.2.gemfile
         | 
| 9 | 
            +
              - rvm: 2.5
         | 
| 10 | 
            +
                gemfile: gemfiles/rails4.2.gemfile
         | 
| 11 | 
            +
              - rvm: 2.2
         | 
| 12 | 
            +
                gemfile: gemfiles/rails3.2.gemfile
         | 
| 12 13 |  | 
| 13 14 | 
             
            script: bundle exec rspec spec
         | 
    
        data/Gemfile
    CHANGED
    
    
    
        data/README.md
    CHANGED
    
    | @@ -1,40 +1,40 @@ | |
| 1 | 
            -
            #  | 
| 1 | 
            +
            # Standby - Read from standby databases for ActiveRecord (formerly Slavery)
         | 
| 2 2 |  | 
| 3 3 | 
             
            [](https://travis-ci.org/kenn/slavery)
         | 
| 4 4 |  | 
| 5 | 
            -
             | 
| 5 | 
            +
            Standby 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.
         | 
| 6 6 |  | 
| 7 | 
            -
            Instead, you can do ` | 
| 7 | 
            +
            Instead, you can do `Standby.on_standby { User.count }` to send a particular query to a standby.
         | 
| 8 8 |  | 
| 9 | 
            -
            Background: Probably your app started off with one single database. As it grows, you would upgrade to a master-slave replication for redundancy. At this point, all queries still go to the  | 
| 9 | 
            +
            Background: 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.
         | 
| 10 10 |  | 
| 11 | 
            -
            * Conservative - Safe by default. Installing  | 
| 11 | 
            +
            * Conservative - Safe by default. Installing Standby won't change your app's current behavior.
         | 
| 12 12 | 
             
            * Future proof - No dirty hacks. Simply works as a proxy for `ActiveRecord::Base.connection`.
         | 
| 13 13 | 
             
            * Simple code - Intentionally small. You can read the entire source and completely stay in control.
         | 
| 14 14 |  | 
| 15 | 
            -
             | 
| 15 | 
            +
            Standby works with ActiveRecord 3 or later.
         | 
| 16 16 |  | 
| 17 17 | 
             
            ## Install
         | 
| 18 18 |  | 
| 19 19 | 
             
            Add this line to your application's Gemfile:
         | 
| 20 20 |  | 
| 21 21 | 
             
            ```ruby
         | 
| 22 | 
            -
            gem ' | 
| 22 | 
            +
            gem 'standby'
         | 
| 23 23 | 
             
            ```
         | 
| 24 24 |  | 
| 25 | 
            -
            And create  | 
| 25 | 
            +
            And create standby configs for each environment.
         | 
| 26 26 |  | 
| 27 27 | 
             
            ```yaml
         | 
| 28 28 | 
             
            development:
         | 
| 29 29 | 
             
              database: myapp_development
         | 
| 30 30 |  | 
| 31 | 
            -
             | 
| 31 | 
            +
            development_standby:
         | 
| 32 32 | 
             
              database: myapp_development
         | 
| 33 33 | 
             
            ```
         | 
| 34 34 |  | 
| 35 | 
            -
            By convention, config keys with `[env] | 
| 35 | 
            +
            By convention, config keys with `[env]_standby` are automatically used for standby reads.
         | 
| 36 36 |  | 
| 37 | 
            -
            Notice that we just copied the settings of `development` to ` | 
| 37 | 
            +
            Notice 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.
         | 
| 38 38 |  | 
| 39 39 | 
             
            In case you prefer DRYer definition, YAML's aliasing and key merging might help.
         | 
| 40 40 |  | 
| @@ -47,7 +47,7 @@ common: &common | |
| 47 47 | 
             
            development:
         | 
| 48 48 | 
             
              <<: *common
         | 
| 49 49 |  | 
| 50 | 
            -
             | 
| 50 | 
            +
            development_standby:
         | 
| 51 51 | 
             
              <<: *common
         | 
| 52 52 | 
             
            ```
         | 
| 53 53 |  | 
| @@ -55,46 +55,46 @@ Optionally, you can use a database url for your connections: | |
| 55 55 |  | 
| 56 56 | 
             
            ```yaml
         | 
| 57 57 | 
             
            development: postgres://root:@localhost:5432/myapp_development
         | 
| 58 | 
            -
             | 
| 58 | 
            +
            development_standby: postgres://root:@localhost:5432/myapp_development_standby
         | 
| 59 59 | 
             
            ```
         | 
| 60 60 |  | 
| 61 | 
            -
            At this point,  | 
| 61 | 
            +
            At this point, Standby does nothing. Run tests and confirm that nothing is broken.
         | 
| 62 62 |  | 
| 63 63 | 
             
            ## Usage
         | 
| 64 64 |  | 
| 65 | 
            -
            To start using  | 
| 65 | 
            +
            To start using Standby, you need to add `Standby.on_standby` in your code. Queries in the `Standby.on_standby` block run on the standby.
         | 
| 66 66 |  | 
| 67 67 | 
             
            ```ruby
         | 
| 68 | 
            -
             | 
| 69 | 
            -
             | 
| 68 | 
            +
            Standby.on_standby { User.count }   # => runs on standby
         | 
| 69 | 
            +
            Standby.on_standby(:two) { User.count }  # => runs on another standby configured as `development_standby_two`
         | 
| 70 70 | 
             
            ```
         | 
| 71 71 |  | 
| 72 | 
            -
            You can nest ` | 
| 72 | 
            +
            You can nest `on_standby` and `on_primary` interchangeably. The following code works as expected.
         | 
| 73 73 |  | 
| 74 74 | 
             
            ```ruby
         | 
| 75 | 
            -
             | 
| 75 | 
            +
            Standby.on_standby do
         | 
| 76 76 | 
             
              ...
         | 
| 77 | 
            -
               | 
| 77 | 
            +
              Standby.on_primary do
         | 
| 78 78 | 
             
                ...
         | 
| 79 79 | 
             
              end
         | 
| 80 80 | 
             
              ...
         | 
| 81 81 | 
             
            end
         | 
| 82 82 | 
             
            ```
         | 
| 83 83 |  | 
| 84 | 
            -
            Alternatively, you may call ` | 
| 84 | 
            +
            Alternatively, you may call `on_standby` directly on the scope, so that the query will be read from standby when it's executed.
         | 
| 85 85 |  | 
| 86 86 | 
             
            ```ruby
         | 
| 87 | 
            -
            User. | 
| 87 | 
            +
            User.on_standby.where(active: true).count
         | 
| 88 88 | 
             
            ```
         | 
| 89 89 |  | 
| 90 | 
            -
            Caveat: `pluck` is not supported by the scope syntax, you still need ` | 
| 90 | 
            +
            Caveat: `pluck` is not supported by the scope syntax, you still need `Standby.on_standby` in this case.
         | 
| 91 91 |  | 
| 92 92 | 
             
            ## Read-only user
         | 
| 93 93 |  | 
| 94 | 
            -
            For an extra safeguard, it is recommended to use a read-only user for  | 
| 94 | 
            +
            For an extra safeguard, it is recommended to use a read-only user for standby access.
         | 
| 95 95 |  | 
| 96 96 | 
             
            ```yaml
         | 
| 97 | 
            -
             | 
| 97 | 
            +
            development_standby:
         | 
| 98 98 | 
             
              <<: *common
         | 
| 99 99 | 
             
              username: readonly
         | 
| 100 100 | 
             
            ```
         | 
| @@ -105,62 +105,85 @@ With MySQL, `GRANT SELECT` creates a read-only user. | |
| 105 105 | 
             
            GRANT SELECT ON *.* TO 'readonly'@'localhost';
         | 
| 106 106 | 
             
            ```
         | 
| 107 107 |  | 
| 108 | 
            -
            With this user, writes on  | 
| 108 | 
            +
            With this user, writes on a standby should raise an exception.
         | 
| 109 109 |  | 
| 110 110 | 
             
            ```ruby
         | 
| 111 | 
            -
             | 
| 111 | 
            +
            Standby.on_standby { User.create }  # => ActiveRecord::StatementInvalid: Mysql2::Error: INSERT command denied...
         | 
| 112 112 | 
             
            ```
         | 
| 113 113 |  | 
| 114 114 | 
             
            With Postgres you can set the entire database to be readonly:
         | 
| 115 115 |  | 
| 116 116 | 
             
            ```SQL
         | 
| 117 | 
            -
            ALTER DATABASE  | 
| 117 | 
            +
            ALTER DATABASE myapp_development_standby SET default_transaction_read_only = true;
         | 
| 118 118 | 
             
            ```
         | 
| 119 119 |  | 
| 120 120 | 
             
            It is a good idea to confirm this behavior in your test code as well.
         | 
| 121 121 |  | 
| 122 122 | 
             
            ## Disable temporarily
         | 
| 123 123 |  | 
| 124 | 
            -
            You can quickly disable  | 
| 124 | 
            +
            You can quickly disable standby reads by dropping the following line in `config/initializers/standby.rb`.
         | 
| 125 125 |  | 
| 126 126 | 
             
            ```ruby
         | 
| 127 | 
            -
             | 
| 127 | 
            +
            Standby.disabled = true
         | 
| 128 128 | 
             
            ```
         | 
| 129 129 |  | 
| 130 | 
            -
            With this line,  | 
| 130 | 
            +
            With this line, Standby stops connection switching and all queries go to the primary.
         | 
| 131 131 |  | 
| 132 | 
            -
            This may be useful when one of the  | 
| 132 | 
            +
            This 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.
         | 
| 133 133 |  | 
| 134 134 | 
             
            ## Transactional fixtures
         | 
| 135 135 |  | 
| 136 136 | 
             
            When `use_transactional_fixtures` is set to `true`, it's NOT recommended to
         | 
| 137 | 
            -
            write to the database besides fixtures, since the  | 
| 138 | 
            -
            of changes performed in the  | 
| 137 | 
            +
            write to the database besides fixtures, since the standby connection is not aware
         | 
| 138 | 
            +
            of changes performed in the primary connection due to [transaction isolation](https://en.wikipedia.org/wiki/Isolation_(database_systems)).
         | 
| 139 139 |  | 
| 140 | 
            -
            In that case, you are suggested to disable  | 
| 140 | 
            +
            In that case, you are suggested to disable Standby in the test environment by
         | 
| 141 141 | 
             
            putting the following in `test/test_helper.rb`
         | 
| 142 142 | 
             
            (or `spec/spec_helper.rb` for RSpec users):
         | 
| 143 143 |  | 
| 144 144 | 
             
            ```ruby
         | 
| 145 | 
            -
             | 
| 145 | 
            +
            Standby.disabled = true
         | 
| 146 146 | 
             
            ```
         | 
| 147 147 |  | 
| 148 | 
            +
            ## Upgrading from version 3 to version 4
         | 
| 149 | 
            +
             | 
| 150 | 
            +
            The gem name has been changed from `slavery` to `standby`.
         | 
| 151 | 
            +
             | 
| 152 | 
            +
            Update your Gemfile
         | 
| 153 | 
            +
             | 
| 154 | 
            +
            ```ruby
         | 
| 155 | 
            +
            gem 'standby'
         | 
| 156 | 
            +
            ```
         | 
| 157 | 
            +
             | 
| 158 | 
            +
            Replace `Slavery` with `Standby`, `on_slave` with `on_standby`, and `on_master` with `on_primary`.
         | 
| 159 | 
            +
             | 
| 160 | 
            +
            ```sh
         | 
| 161 | 
            +
            grep -e Slavery **/*.rake **/*.rb -s -l | xargs sed -i "" "s|Slavery|Standby|g"
         | 
| 162 | 
            +
            grep -e on_slave **/*.rake **/*.rb -s -l | xargs sed -i "" "s|on_slave|on_standby|g"
         | 
| 163 | 
            +
            grep -e on_master **/*.rake **/*.rb -s -l | xargs sed -i "" "s|on_master|on_primary|g"
         | 
| 164 | 
            +
            ```
         | 
| 165 | 
            +
             | 
| 166 | 
            +
            ## Upgrading from version 2 to version 3
         | 
| 167 | 
            +
             | 
| 168 | 
            +
            Please note that `Standby.spec_key=` method has been removed from version 3.
         | 
| 169 | 
            +
             | 
| 148 170 | 
             
            ## Support for non-Rails apps
         | 
| 149 171 |  | 
| 150 172 | 
             
            If 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:
         | 
| 151 173 |  | 
| 152 174 | 
             
            ```ruby
         | 
| 153 | 
            -
            require ' | 
| 175 | 
            +
            require 'standby'
         | 
| 154 176 |  | 
| 155 177 | 
             
            ActiveRecord::Base.configurations = {
         | 
| 156 | 
            -
              'development' => | 
| 157 | 
            -
              ' | 
| 178 | 
            +
              'development' =>          { adapter: 'mysql2', ... },
         | 
| 179 | 
            +
              'development_standby' =>  { adapter: 'mysql2', ... }
         | 
| 158 180 | 
             
            }
         | 
| 159 181 | 
             
            ActiveRecord::Base.establish_connection(:development)
         | 
| 160 182 | 
             
            ```
         | 
| 161 183 |  | 
| 162 184 | 
             
            ## Changelog
         | 
| 163 185 |  | 
| 164 | 
            -
            *  | 
| 186 | 
            +
            * v4.0.0: Rename gem from Slavery to Standby
         | 
| 187 | 
            +
            * v3.0.0: Support for multiple standby targets ([@punchh](https://github.com/punchh))
         | 
| 165 188 | 
             
            * v2.1.0: Debug log support / Database URL support / Rails 3.2 & 4.0 compatibility (Thanks to [@citrus](https://github.com/citrus))
         | 
| 166 189 | 
             
            * v2.0.0: Rails 5 support
         | 
    
        data/Rakefile
    CHANGED
    
    
    
        data/gemfiles/rails3.2.gemfile
    CHANGED
    
    
    
        data/gemfiles/rails4.2.gemfile
    CHANGED
    
    
    
        data/lib/standby.rb
    ADDED
    
    | @@ -0,0 +1,29 @@ | |
| 1 | 
            +
            require 'active_record'
         | 
| 2 | 
            +
            require 'standby/version'
         | 
| 3 | 
            +
            require 'standby/base'
         | 
| 4 | 
            +
            require 'standby/error'
         | 
| 5 | 
            +
            require 'standby/connection_holder'
         | 
| 6 | 
            +
            require 'standby/transaction'
         | 
| 7 | 
            +
            require 'standby/active_record/base'
         | 
| 8 | 
            +
            require 'standby/active_record/connection_handling'
         | 
| 9 | 
            +
            require 'standby/active_record/relation'
         | 
| 10 | 
            +
            require 'standby/active_record/log_subscriber'
         | 
| 11 | 
            +
             | 
| 12 | 
            +
            module Standby
         | 
| 13 | 
            +
              class << self
         | 
| 14 | 
            +
                attr_accessor :disabled
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                def standby_connections
         | 
| 17 | 
            +
                  @standby_connections ||= {}
         | 
| 18 | 
            +
                end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                def on_standby(name = :null_state, &block)
         | 
| 21 | 
            +
                  raise Standby::Error.new('invalid standby target') unless name.is_a?(Symbol)
         | 
| 22 | 
            +
                  Base.new(name).run &block
         | 
| 23 | 
            +
                end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                def on_primary(&block)
         | 
| 26 | 
            +
                  Base.new(:primary).run &block
         | 
| 27 | 
            +
                end
         | 
| 28 | 
            +
              end
         | 
| 29 | 
            +
            end
         | 
| @@ -0,0 +1,25 @@ | |
| 1 | 
            +
            module ActiveRecord
         | 
| 2 | 
            +
              class Base
         | 
| 3 | 
            +
                class << self
         | 
| 4 | 
            +
                  alias_method :connection_without_standby, :connection
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                  def connection
         | 
| 7 | 
            +
                    case Thread.current[:_standby]
         | 
| 8 | 
            +
                    when :primary, NilClass
         | 
| 9 | 
            +
                      connection_without_standby
         | 
| 10 | 
            +
                    else
         | 
| 11 | 
            +
                      Standby.connection_holder(Thread.current[:_standby]).connection_without_standby
         | 
| 12 | 
            +
                    end
         | 
| 13 | 
            +
                  end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                  # Generate scope at top level e.g. User.on_standby
         | 
| 16 | 
            +
                  def on_standby(name = :null_state)
         | 
| 17 | 
            +
                    # Why where(nil)?
         | 
| 18 | 
            +
                    # http://stackoverflow.com/questions/18198963/with-rails-4-model-scoped-is-deprecated-but-model-all-cant-replace-it
         | 
| 19 | 
            +
                    context = where(nil)
         | 
| 20 | 
            +
                    context.standby_target = name || :null_state
         | 
| 21 | 
            +
                    context
         | 
| 22 | 
            +
                  end
         | 
| 23 | 
            +
                end
         | 
| 24 | 
            +
              end
         | 
| 25 | 
            +
            end
         | 
| 
            File without changes
         | 
| @@ -0,0 +1,12 @@ | |
| 1 | 
            +
            module ActiveRecord
         | 
| 2 | 
            +
              class LogSubscriber
         | 
| 3 | 
            +
             | 
| 4 | 
            +
                alias_method :debug_without_standby, :debug
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                def debug(msg)
         | 
| 7 | 
            +
                  db = Standby.disabled ? "" : color("[#{Thread.current[:_standby] || "primary"}]", ActiveSupport::LogSubscriber::GREEN, true)
         | 
| 8 | 
            +
                  debug_without_standby(db + msg)
         | 
| 9 | 
            +
                end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
              end
         | 
| 12 | 
            +
            end
         | 
| @@ -0,0 +1,28 @@ | |
| 1 | 
            +
            module ActiveRecord
         | 
| 2 | 
            +
              class Relation
         | 
| 3 | 
            +
                attr_accessor :standby_target
         | 
| 4 | 
            +
             | 
| 5 | 
            +
                # Supports queries like User.on_standby.to_a
         | 
| 6 | 
            +
                alias_method :exec_queries_without_standby, :exec_queries
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                def exec_queries
         | 
| 9 | 
            +
                  if standby_target
         | 
| 10 | 
            +
                    Standby.on_standby(standby_target) { exec_queries_without_standby }
         | 
| 11 | 
            +
                  else
         | 
| 12 | 
            +
                    exec_queries_without_standby
         | 
| 13 | 
            +
                  end
         | 
| 14 | 
            +
                end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
             | 
| 17 | 
            +
                # Supports queries like User.on_standby.count
         | 
| 18 | 
            +
                alias_method :calculate_without_standby, :calculate
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                def calculate(*args)
         | 
| 21 | 
            +
                  if standby_target
         | 
| 22 | 
            +
                    Standby.on_standby(standby_target) { calculate_without_standby(*args) }
         | 
| 23 | 
            +
                  else
         | 
| 24 | 
            +
                    calculate_without_standby(*args)
         | 
| 25 | 
            +
                  end
         | 
| 26 | 
            +
                end
         | 
| 27 | 
            +
              end
         | 
| 28 | 
            +
            end
         | 
    
        data/lib/standby/base.rb
    ADDED
    
    | @@ -0,0 +1,40 @@ | |
| 1 | 
            +
            module Standby
         | 
| 2 | 
            +
              class Base
         | 
| 3 | 
            +
                def initialize(target)
         | 
| 4 | 
            +
                  @target = decide_with(target)
         | 
| 5 | 
            +
                end
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                def run(&block)
         | 
| 8 | 
            +
                  run_on @target, &block
         | 
| 9 | 
            +
                end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
              private
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                def decide_with(target)
         | 
| 14 | 
            +
                  if Standby.disabled || target == :primary
         | 
| 15 | 
            +
                    :primary
         | 
| 16 | 
            +
                  elsif inside_transaction?
         | 
| 17 | 
            +
                    raise Standby::Error.new('on_standby cannot be used inside transaction block!')
         | 
| 18 | 
            +
                  elsif target == :null_state
         | 
| 19 | 
            +
                    :standby
         | 
| 20 | 
            +
                  elsif target.present?
         | 
| 21 | 
            +
                    "standby_#{target}".to_sym
         | 
| 22 | 
            +
                  else
         | 
| 23 | 
            +
                    raise Standby::Error.new('on_standby cannot be used with a nil target!')
         | 
| 24 | 
            +
                  end
         | 
| 25 | 
            +
                end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                def inside_transaction?
         | 
| 28 | 
            +
                  open_transactions = run_on(:primary) { ActiveRecord::Base.connection.open_transactions }
         | 
| 29 | 
            +
                  open_transactions > Standby::Transaction.base_depth
         | 
| 30 | 
            +
                end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                def run_on(target)
         | 
| 33 | 
            +
                  backup = Thread.current[:_standby] # Save for recursive nested calls
         | 
| 34 | 
            +
                  Thread.current[:_standby] = target
         | 
| 35 | 
            +
                  yield
         | 
| 36 | 
            +
                ensure
         | 
| 37 | 
            +
                  Thread.current[:_standby] = backup
         | 
| 38 | 
            +
                end
         | 
| 39 | 
            +
              end
         | 
| 40 | 
            +
            end
         | 
| @@ -1,4 +1,4 @@ | |
| 1 | 
            -
            module  | 
| 1 | 
            +
            module Standby
         | 
| 2 2 | 
             
              class ConnectionHolder < ActiveRecord::Base
         | 
| 3 3 | 
             
                self.abstract_class = true
         | 
| 4 4 |  | 
| @@ -6,7 +6,7 @@ module Slavery | |
| 6 6 | 
             
                  # for delayed activation
         | 
| 7 7 | 
             
                  def activate(target)
         | 
| 8 8 | 
             
                    spec = ActiveRecord::Base.configurations["#{ActiveRecord::ConnectionHandling::RAILS_ENV.call}_#{target}"]
         | 
| 9 | 
            -
                    raise Error.new(" | 
| 9 | 
            +
                    raise Error.new("Standby target '#{target}' is invalid!") if spec.nil?
         | 
| 10 10 | 
             
                    establish_connection spec
         | 
| 11 11 | 
             
                  end
         | 
| 12 12 | 
             
                end
         | 
| @@ -14,9 +14,9 @@ module Slavery | |
| 14 14 |  | 
| 15 15 | 
             
              class << self
         | 
| 16 16 | 
             
                def connection_holder(target)
         | 
| 17 | 
            -
                  klass_name = " | 
| 18 | 
            -
                   | 
| 19 | 
            -
                    klass = Class.new( | 
| 17 | 
            +
                  klass_name = "Standby#{target.to_s.camelize}ConnectionHolder"
         | 
| 18 | 
            +
                  standby_connections[klass_name] ||= begin
         | 
| 19 | 
            +
                    klass = Class.new(Standby::ConnectionHolder) do
         | 
| 20 20 | 
             
                      self.abstract_class = true
         | 
| 21 21 | 
             
                    end
         | 
| 22 22 | 
             
                    Object.const_set(klass_name, klass)
         | 
    
        data/slavery.gemspec
    CHANGED
    
    | @@ -1,11 +1,14 @@ | |
| 1 1 | 
             
            # -*- encoding: utf-8 -*-
         | 
| 2 2 | 
             
            lib = File.expand_path('../lib', __FILE__)
         | 
| 3 3 | 
             
            $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
         | 
| 4 | 
            -
            require ' | 
| 4 | 
            +
            require 'standby/version'
         | 
| 5 5 |  | 
| 6 6 | 
             
            Gem::Specification.new do |gem|
         | 
| 7 | 
            +
              gem.post_install_message = 'The slavery gem has been deprecated and has ' \
         | 
| 8 | 
            +
                                         'been replaced by standby. Please switch to ' \
         | 
| 9 | 
            +
                                         'standby as soon as possible.'
         | 
| 7 10 | 
             
              gem.name          = 'slavery'
         | 
| 8 | 
            -
              gem.version       =  | 
| 11 | 
            +
              gem.version       = Standby::VERSION
         | 
| 9 12 | 
             
              gem.authors       = ['Kenn Ejima']
         | 
| 10 13 | 
             
              gem.email         = ['kenn.ejima@gmail.com']
         | 
| 11 14 | 
             
              gem.description   = %q{Simple, conservative slave reads for ActiveRecord}
         | 
| @@ -13,7 +16,7 @@ Gem::Specification.new do |gem| | |
| 13 16 | 
             
              gem.homepage      = 'https://github.com/kenn/slavery'
         | 
| 14 17 |  | 
| 15 18 | 
             
              gem.files         = `git ls-files`.split($/)
         | 
| 16 | 
            -
              gem.executables   = gem.files.grep(%r{^ | 
| 19 | 
            +
              gem.executables   = gem.files.grep(%r{^exe/}).map{ |f| File.basename(f) }
         | 
| 17 20 | 
             
              gem.test_files    = gem.files.grep(%r{^(test|spec|features)/})
         | 
| 18 21 | 
             
              gem.require_paths = ['lib']
         | 
| 19 22 |  | 
| @@ -10,30 +10,30 @@ describe ActiveRecord::LogSubscriber do | |
| 10 10 |  | 
| 11 11 | 
             
                before do
         | 
| 12 12 | 
             
                  ActiveRecord::Base.logger = logger
         | 
| 13 | 
            -
                  @backup_disabled =  | 
| 13 | 
            +
                  @backup_disabled = Standby.disabled
         | 
| 14 14 | 
             
                end
         | 
| 15 15 |  | 
| 16 16 | 
             
                after do
         | 
| 17 | 
            -
                   | 
| 17 | 
            +
                  Standby.disabled = @backup_disabled
         | 
| 18 18 | 
             
                end
         | 
| 19 19 |  | 
| 20 | 
            -
                it 'it prefixes log messages with  | 
| 20 | 
            +
                it 'it prefixes log messages with primary' do
         | 
| 21 21 | 
             
                  User.count
         | 
| 22 22 | 
             
                  log.rewind
         | 
| 23 | 
            -
                  expect(log.read).to include('[ | 
| 23 | 
            +
                  expect(log.read).to include('[primary]')
         | 
| 24 24 | 
             
                end
         | 
| 25 25 |  | 
| 26 | 
            -
                it 'it prefixes log messages with the  | 
| 27 | 
            -
                  User. | 
| 26 | 
            +
                it 'it prefixes log messages with the standby connection' do
         | 
| 27 | 
            +
                  User.on_standby.count
         | 
| 28 28 | 
             
                  log.rewind
         | 
| 29 | 
            -
                  expect(log.read).to include('[ | 
| 29 | 
            +
                  expect(log.read).to include('[standby]')
         | 
| 30 30 | 
             
                end
         | 
| 31 31 |  | 
| 32 | 
            -
                it 'it does nothing when  | 
| 33 | 
            -
                   | 
| 32 | 
            +
                it 'it does nothing when standby is disabled' do
         | 
| 33 | 
            +
                  Standby.disabled = true
         | 
| 34 34 | 
             
                  User.count
         | 
| 35 35 | 
             
                  log.rewind
         | 
| 36 | 
            -
                  expect(log.read).to_not include('[ | 
| 36 | 
            +
                  expect(log.read).to_not include('[primary]')
         | 
| 37 37 | 
             
                end
         | 
| 38 38 |  | 
| 39 39 | 
             
              end
         | 
    
        data/spec/configuration_spec.rb
    CHANGED
    
    | @@ -3,32 +3,32 @@ require 'spec_helper' | |
| 3 3 | 
             
            describe 'configuration' do
         | 
| 4 4 | 
             
              before do
         | 
| 5 5 | 
             
                # Backup connection and configs
         | 
| 6 | 
            -
                @backup_conn =  | 
| 6 | 
            +
                @backup_conn = Standby.instance_variable_get :@standby_connections
         | 
| 7 7 | 
             
                @backup_config = ActiveRecord::Base.configurations.dup
         | 
| 8 | 
            -
                @backup_disabled =  | 
| 8 | 
            +
                @backup_disabled = Standby.disabled
         | 
| 9 9 | 
             
                @backup_conn.each_key do |klass_name|
         | 
| 10 10 | 
             
                  Object.send(:remove_const, klass_name) if Object.const_defined?(klass_name)
         | 
| 11 11 | 
             
                end
         | 
| 12 | 
            -
                 | 
| 12 | 
            +
                Standby.instance_variable_set :@standby_connections, {}
         | 
| 13 13 | 
             
              end
         | 
| 14 14 |  | 
| 15 15 | 
             
              after do
         | 
| 16 16 | 
             
                # Restore connection and configs
         | 
| 17 | 
            -
                 | 
| 17 | 
            +
                Standby.instance_variable_set :@standby_connections, @backup_conn
         | 
| 18 18 | 
             
                ActiveRecord::Base.configurations = @backup_config
         | 
| 19 | 
            -
                 | 
| 19 | 
            +
                Standby.disabled = @backup_disabled
         | 
| 20 20 | 
             
              end
         | 
| 21 21 |  | 
| 22 | 
            -
              it 'raises error if  | 
| 23 | 
            -
                ActiveRecord::Base.configurations[' | 
| 22 | 
            +
              it 'raises error if standby configuration not specified' do
         | 
| 23 | 
            +
                ActiveRecord::Base.configurations['test_standby'] = nil
         | 
| 24 24 |  | 
| 25 | 
            -
                expect {  | 
| 25 | 
            +
                expect { Standby.on_standby { User.count } }.to raise_error(Standby::Error)
         | 
| 26 26 | 
             
              end
         | 
| 27 27 |  | 
| 28 | 
            -
              it 'connects to  | 
| 29 | 
            -
                ActiveRecord::Base.configurations[' | 
| 30 | 
            -
                 | 
| 28 | 
            +
              it 'connects to primary if standby configuration is disabled' do
         | 
| 29 | 
            +
                ActiveRecord::Base.configurations['test_standby'] = nil
         | 
| 30 | 
            +
                Standby.disabled = true
         | 
| 31 31 |  | 
| 32 | 
            -
                expect( | 
| 32 | 
            +
                expect(Standby.on_standby { User.count }).to be 2
         | 
| 33 33 | 
             
              end
         | 
| 34 34 | 
             
            end
         | 
    
        data/spec/slavery_spec.rb
    CHANGED
    
    | @@ -1,66 +1,66 @@ | |
| 1 1 | 
             
            require 'spec_helper'
         | 
| 2 2 |  | 
| 3 | 
            -
            describe  | 
| 4 | 
            -
              def  | 
| 5 | 
            -
                Thread.current[: | 
| 3 | 
            +
            describe Standby do
         | 
| 4 | 
            +
              def standby_value
         | 
| 5 | 
            +
                Thread.current[:_standby]
         | 
| 6 6 | 
             
              end
         | 
| 7 7 |  | 
| 8 | 
            -
              def  | 
| 9 | 
            -
                 | 
| 8 | 
            +
              def on_standby?
         | 
| 9 | 
            +
                standby_value == :standby
         | 
| 10 10 | 
             
              end
         | 
| 11 11 |  | 
| 12 12 | 
             
              it 'sets thread local' do
         | 
| 13 | 
            -
                 | 
| 14 | 
            -
                 | 
| 15 | 
            -
                 | 
| 13 | 
            +
                Standby.on_primary { expect(standby_value).to be :primary }
         | 
| 14 | 
            +
                Standby.on_standby { expect(standby_value).to be :standby }
         | 
| 15 | 
            +
                Standby.on_standby(:two) { expect(standby_value).to be :standby_two}
         | 
| 16 16 | 
             
              end
         | 
| 17 17 |  | 
| 18 18 | 
             
              it 'returns value from block' do
         | 
| 19 | 
            -
                expect( | 
| 20 | 
            -
                expect( | 
| 21 | 
            -
                expect( | 
| 19 | 
            +
                expect(Standby.on_primary { User.count }).to be 2
         | 
| 20 | 
            +
                expect(Standby.on_standby  { User.count }).to be 1
         | 
| 21 | 
            +
                expect(Standby.on_standby(:two) { User.count }).to be 0
         | 
| 22 22 | 
             
              end
         | 
| 23 23 |  | 
| 24 24 | 
             
              it 'handles nested calls' do
         | 
| 25 | 
            -
                #  | 
| 26 | 
            -
                 | 
| 27 | 
            -
                  expect( | 
| 25 | 
            +
                # Standby -> Standby
         | 
| 26 | 
            +
                Standby.on_standby do
         | 
| 27 | 
            +
                  expect(on_standby?).to be true
         | 
| 28 28 |  | 
| 29 | 
            -
                   | 
| 30 | 
            -
                    expect( | 
| 29 | 
            +
                  Standby.on_standby do
         | 
| 30 | 
            +
                    expect(on_standby?).to be true
         | 
| 31 31 | 
             
                  end
         | 
| 32 32 |  | 
| 33 | 
            -
                  expect( | 
| 33 | 
            +
                  expect(on_standby?).to be true
         | 
| 34 34 | 
             
                end
         | 
| 35 35 |  | 
| 36 | 
            -
                #  | 
| 37 | 
            -
                 | 
| 38 | 
            -
                  expect( | 
| 36 | 
            +
                # Standby -> Primary
         | 
| 37 | 
            +
                Standby.on_standby do
         | 
| 38 | 
            +
                  expect(on_standby?).to be true
         | 
| 39 39 |  | 
| 40 | 
            -
                   | 
| 41 | 
            -
                    expect( | 
| 40 | 
            +
                  Standby.on_primary do
         | 
| 41 | 
            +
                    expect(on_standby?).to be false
         | 
| 42 42 | 
             
                  end
         | 
| 43 43 |  | 
| 44 | 
            -
                  expect( | 
| 44 | 
            +
                  expect(on_standby?).to be true
         | 
| 45 45 | 
             
                end
         | 
| 46 46 | 
             
              end
         | 
| 47 47 |  | 
| 48 48 | 
             
              it 'raises error in transaction' do
         | 
| 49 49 | 
             
                User.transaction do
         | 
| 50 | 
            -
                  expect {  | 
| 50 | 
            +
                  expect { Standby.on_standby { User.first } }.to raise_error(Standby::Error)
         | 
| 51 51 | 
             
                end
         | 
| 52 52 | 
             
              end
         | 
| 53 53 |  | 
| 54 54 | 
             
              it 'disables by configuration' do
         | 
| 55 | 
            -
                backup =  | 
| 55 | 
            +
                backup = Standby.disabled
         | 
| 56 56 |  | 
| 57 | 
            -
                 | 
| 58 | 
            -
                 | 
| 57 | 
            +
                Standby.disabled = false
         | 
| 58 | 
            +
                Standby.on_standby { expect(standby_value).to be :standby }
         | 
| 59 59 |  | 
| 60 | 
            -
                 | 
| 61 | 
            -
                 | 
| 60 | 
            +
                Standby.disabled = true
         | 
| 61 | 
            +
                Standby.on_standby { expect(standby_value).to be :primary }
         | 
| 62 62 |  | 
| 63 | 
            -
                 | 
| 63 | 
            +
                Standby.disabled = backup
         | 
| 64 64 | 
             
              end
         | 
| 65 65 |  | 
| 66 66 | 
             
              it 'avoids stack overflow with 3rdparty gem that defines alias_method. namely newrelic...' do
         | 
| @@ -79,29 +79,29 @@ describe Slavery do | |
| 79 79 | 
             
                end
         | 
| 80 80 | 
             
              end
         | 
| 81 81 |  | 
| 82 | 
            -
              it 'works with nils like  | 
| 83 | 
            -
                expect(User. | 
| 82 | 
            +
              it 'works with nils like standby' do
         | 
| 83 | 
            +
                expect(User.on_standby(nil).count).to be User.on_standby.count
         | 
| 84 84 | 
             
              end
         | 
| 85 85 |  | 
| 86 86 | 
             
              it 'raises on blanks and strings' do
         | 
| 87 | 
            -
                expect { User. | 
| 88 | 
            -
                expect { User. | 
| 89 | 
            -
                expect { User. | 
| 87 | 
            +
                expect { User.on_standby("").count }.to raise_error(Standby::Error)
         | 
| 88 | 
            +
                expect { User.on_standby("two").count }.to raise_error(Standby::Error)
         | 
| 89 | 
            +
                expect { User.on_standby("standby").count }.to raise_error(Standby::Error)
         | 
| 90 90 | 
             
              end
         | 
| 91 91 |  | 
| 92 92 | 
             
              it 'raises with non existent extension' do
         | 
| 93 | 
            -
                expect {  | 
| 93 | 
            +
                expect { Standby.on_standby(:non_existent) { User.first } }.to raise_error(Standby::Error)
         | 
| 94 94 | 
             
              end
         | 
| 95 95 |  | 
| 96 96 | 
             
              it 'works with any scopes' do
         | 
| 97 97 | 
             
                expect(User.count).to be 2
         | 
| 98 | 
            -
                expect(User. | 
| 99 | 
            -
                expect(User. | 
| 98 | 
            +
                expect(User.on_standby(:two).count).to be 0
         | 
| 99 | 
            +
                expect(User.on_standby.count).to be 1
         | 
| 100 100 |  | 
| 101 101 | 
             
                # Why where(nil)?
         | 
| 102 102 | 
             
                # http://stackoverflow.com/questions/18198963/with-rails-4-model-scoped-is-deprecated-but-model-all-cant-replace-it
         | 
| 103 103 | 
             
                expect(User.where(nil).to_a.size).to be 2
         | 
| 104 | 
            -
                expect(User. | 
| 105 | 
            -
                expect(User. | 
| 104 | 
            +
                expect(User.on_standby(:two).where(nil).to_a.size).to be 0
         | 
| 105 | 
            +
                expect(User.on_standby.where(nil).to_a.size).to be 1
         | 
| 106 106 | 
             
              end
         | 
| 107 107 | 
             
            end
         | 
    
        data/spec/spec_helper.rb
    CHANGED
    
    | @@ -3,13 +3,13 @@ require 'bundler/setup' | |
| 3 3 |  | 
| 4 4 | 
             
            ENV['RACK_ENV'] = 'test'
         | 
| 5 5 |  | 
| 6 | 
            -
            require ' | 
| 6 | 
            +
            require 'standby'
         | 
| 7 7 |  | 
| 8 8 | 
             
            ActiveRecord::Base.configurations = {
         | 
| 9 9 | 
             
              'test'            =>  { 'adapter' => 'sqlite3', 'database' => 'test_db' },
         | 
| 10 | 
            -
              ' | 
| 11 | 
            -
              ' | 
| 12 | 
            -
              ' | 
| 10 | 
            +
              'test_standby'      =>  { 'adapter' => 'sqlite3', 'database' => 'test_standby_one' },
         | 
| 11 | 
            +
              'test_standby_two'  =>  { 'adapter' => 'sqlite3', 'database' => 'test_standby_two'},
         | 
| 12 | 
            +
              'test_standby_url'  =>  'postgres://root:@localhost:5432/test_standby'
         | 
| 13 13 | 
             
            }
         | 
| 14 14 |  | 
| 15 15 | 
             
            # Prepare databases
         | 
| @@ -23,23 +23,23 @@ end | |
| 23 23 |  | 
| 24 24 | 
             
            class Seeder
         | 
| 25 25 | 
             
              def run
         | 
| 26 | 
            -
                # Populate on  | 
| 26 | 
            +
                # Populate on primary
         | 
| 27 27 | 
             
                connect(:test)
         | 
| 28 28 | 
             
                create_tables
         | 
| 29 29 | 
             
                User.create
         | 
| 30 30 | 
             
                User.create
         | 
| 31 31 | 
             
                User.first.items.create
         | 
| 32 32 |  | 
| 33 | 
            -
                # Populate on  | 
| 34 | 
            -
                connect(: | 
| 33 | 
            +
                # Populate on standby, emulating replication lag
         | 
| 34 | 
            +
                connect(:test_standby)
         | 
| 35 35 | 
             
                create_tables
         | 
| 36 36 | 
             
                User.create
         | 
| 37 37 |  | 
| 38 | 
            -
                # Populate on  | 
| 39 | 
            -
                connect(: | 
| 38 | 
            +
                # Populate on standby two
         | 
| 39 | 
            +
                connect(:test_standby_two)
         | 
| 40 40 | 
             
                create_tables
         | 
| 41 41 |  | 
| 42 | 
            -
                # Reconnect to  | 
| 42 | 
            +
                # Reconnect to primary
         | 
| 43 43 | 
             
                connect(:test)
         | 
| 44 44 | 
             
              end
         | 
| 45 45 |  | 
    
        data/standby.gemspec
    ADDED
    
    | @@ -0,0 +1,24 @@ | |
| 1 | 
            +
            # -*- encoding: utf-8 -*-
         | 
| 2 | 
            +
            lib = File.expand_path('../lib', __FILE__)
         | 
| 3 | 
            +
            $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
         | 
| 4 | 
            +
            require 'standby/version'
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            Gem::Specification.new do |gem|
         | 
| 7 | 
            +
              gem.name          = 'standby'
         | 
| 8 | 
            +
              gem.version       = Standby::VERSION
         | 
| 9 | 
            +
              gem.authors       = ['Kenn Ejima']
         | 
| 10 | 
            +
              gem.email         = ['kenn.ejima@gmail.com']
         | 
| 11 | 
            +
              gem.description   = %q{Read from stand-by databases for ActiveRecord}
         | 
| 12 | 
            +
              gem.summary       = %q{Read from stand-by databases for ActiveRecord}
         | 
| 13 | 
            +
              gem.homepage      = 'https://github.com/kenn/standby'
         | 
| 14 | 
            +
             | 
| 15 | 
            +
              gem.files         = `git ls-files`.split($/)
         | 
| 16 | 
            +
              gem.executables   = gem.files.grep(%r{^exe/}).map{ |f| File.basename(f) }
         | 
| 17 | 
            +
              gem.test_files    = gem.files.grep(%r{^(test|spec|features)/})
         | 
| 18 | 
            +
              gem.require_paths = ['lib']
         | 
| 19 | 
            +
             | 
| 20 | 
            +
              gem.add_runtime_dependency 'activerecord', '>= 3.0.0'
         | 
| 21 | 
            +
             | 
| 22 | 
            +
              gem.add_development_dependency 'rspec'
         | 
| 23 | 
            +
              gem.add_development_dependency 'sqlite3'
         | 
| 24 | 
            +
            end
         | 
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: slavery
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version:  | 
| 4 | 
            +
              version: 4.0.0
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Kenn Ejima
         | 
| 8 8 | 
             
            autorequire: 
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date:  | 
| 11 | 
            +
            date: 2018-07-26 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: activerecord
         | 
| @@ -55,8 +55,7 @@ dependencies: | |
| 55 55 | 
             
            description: Simple, conservative slave reads for ActiveRecord
         | 
| 56 56 | 
             
            email:
         | 
| 57 57 | 
             
            - kenn.ejima@gmail.com
         | 
| 58 | 
            -
            executables:
         | 
| 59 | 
            -
            - console
         | 
| 58 | 
            +
            executables: []
         | 
| 60 59 | 
             
            extensions: []
         | 
| 61 60 | 
             
            extra_rdoc_files: []
         | 
| 62 61 | 
             
            files:
         | 
| @@ -70,26 +69,28 @@ files: | |
| 70 69 | 
             
            - bin/console
         | 
| 71 70 | 
             
            - gemfiles/rails3.2.gemfile
         | 
| 72 71 | 
             
            - gemfiles/rails4.2.gemfile
         | 
| 73 | 
            -
            - gemfiles/ | 
| 74 | 
            -
            - lib/ | 
| 75 | 
            -
            - lib/ | 
| 76 | 
            -
            - lib/ | 
| 77 | 
            -
            - lib/ | 
| 78 | 
            -
            - lib/ | 
| 79 | 
            -
            - lib/ | 
| 80 | 
            -
            - lib/ | 
| 81 | 
            -
            - lib/ | 
| 82 | 
            -
            - lib/ | 
| 83 | 
            -
            - lib/ | 
| 72 | 
            +
            - gemfiles/rails5.2.gemfile
         | 
| 73 | 
            +
            - lib/standby.rb
         | 
| 74 | 
            +
            - lib/standby/active_record/base.rb
         | 
| 75 | 
            +
            - lib/standby/active_record/connection_handling.rb
         | 
| 76 | 
            +
            - lib/standby/active_record/log_subscriber.rb
         | 
| 77 | 
            +
            - lib/standby/active_record/relation.rb
         | 
| 78 | 
            +
            - lib/standby/base.rb
         | 
| 79 | 
            +
            - lib/standby/connection_holder.rb
         | 
| 80 | 
            +
            - lib/standby/error.rb
         | 
| 81 | 
            +
            - lib/standby/transaction.rb
         | 
| 82 | 
            +
            - lib/standby/version.rb
         | 
| 84 83 | 
             
            - slavery.gemspec
         | 
| 85 84 | 
             
            - spec/active_record/log_subscriber_spec.rb
         | 
| 86 85 | 
             
            - spec/configuration_spec.rb
         | 
| 87 86 | 
             
            - spec/slavery_spec.rb
         | 
| 88 87 | 
             
            - spec/spec_helper.rb
         | 
| 88 | 
            +
            - standby.gemspec
         | 
| 89 89 | 
             
            homepage: https://github.com/kenn/slavery
         | 
| 90 90 | 
             
            licenses: []
         | 
| 91 91 | 
             
            metadata: {}
         | 
| 92 | 
            -
            post_install_message: 
         | 
| 92 | 
            +
            post_install_message: The slavery gem has been deprecated and has been replaced by
         | 
| 93 | 
            +
              standby. Please switch to standby as soon as possible.
         | 
| 93 94 | 
             
            rdoc_options: []
         | 
| 94 95 | 
             
            require_paths:
         | 
| 95 96 | 
             
            - lib
         | 
| @@ -105,7 +106,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement | |
| 105 106 | 
             
                  version: '0'
         | 
| 106 107 | 
             
            requirements: []
         | 
| 107 108 | 
             
            rubyforge_project: 
         | 
| 108 | 
            -
            rubygems_version: 2.6 | 
| 109 | 
            +
            rubygems_version: 2.7.6
         | 
| 109 110 | 
             
            signing_key: 
         | 
| 110 111 | 
             
            specification_version: 4
         | 
| 111 112 | 
             
            summary: Simple, conservative slave reads for ActiveRecord
         | 
    
        data/gemfiles/rails4.gemfile
    DELETED
    
    
    
        data/lib/slavery.rb
    DELETED
    
    | @@ -1,29 +0,0 @@ | |
| 1 | 
            -
            require 'active_record'
         | 
| 2 | 
            -
            require 'slavery/version'
         | 
| 3 | 
            -
            require 'slavery/base'
         | 
| 4 | 
            -
            require 'slavery/error'
         | 
| 5 | 
            -
            require 'slavery/connection_holder'
         | 
| 6 | 
            -
            require 'slavery/transaction'
         | 
| 7 | 
            -
            require 'slavery/active_record/base'
         | 
| 8 | 
            -
            require 'slavery/active_record/connection_handling'
         | 
| 9 | 
            -
            require 'slavery/active_record/relation'
         | 
| 10 | 
            -
            require 'slavery/active_record/log_subscriber'
         | 
| 11 | 
            -
             | 
| 12 | 
            -
            module Slavery
         | 
| 13 | 
            -
              class << self
         | 
| 14 | 
            -
                attr_accessor :disabled
         | 
| 15 | 
            -
             | 
| 16 | 
            -
                def slave_connections
         | 
| 17 | 
            -
                  @slave_connections ||= {}
         | 
| 18 | 
            -
                end
         | 
| 19 | 
            -
             | 
| 20 | 
            -
                def on_slave(name = :null_state, &block)
         | 
| 21 | 
            -
                  raise Slavery::Error.new('invalid slave target') unless name.is_a?(Symbol)
         | 
| 22 | 
            -
                  Base.new(name).run &block
         | 
| 23 | 
            -
                end
         | 
| 24 | 
            -
             | 
| 25 | 
            -
                def on_master(&block)
         | 
| 26 | 
            -
                  Base.new(:master).run &block
         | 
| 27 | 
            -
                end
         | 
| 28 | 
            -
              end
         | 
| 29 | 
            -
            end
         | 
| @@ -1,25 +0,0 @@ | |
| 1 | 
            -
            module ActiveRecord
         | 
| 2 | 
            -
              class Base
         | 
| 3 | 
            -
                class << self
         | 
| 4 | 
            -
                  alias_method :connection_without_slavery, :connection
         | 
| 5 | 
            -
             | 
| 6 | 
            -
                  def connection
         | 
| 7 | 
            -
                    case Thread.current[:slavery]
         | 
| 8 | 
            -
                    when :master, NilClass
         | 
| 9 | 
            -
                      connection_without_slavery
         | 
| 10 | 
            -
                    else
         | 
| 11 | 
            -
                      Slavery.connection_holder(Thread.current[:slavery]).connection_without_slavery
         | 
| 12 | 
            -
                    end
         | 
| 13 | 
            -
                  end
         | 
| 14 | 
            -
             | 
| 15 | 
            -
                  # Generate scope at top level e.g. User.on_slave
         | 
| 16 | 
            -
                  def on_slave(name = :null_state)
         | 
| 17 | 
            -
                    # Why where(nil)?
         | 
| 18 | 
            -
                    # http://stackoverflow.com/questions/18198963/with-rails-4-model-scoped-is-deprecated-but-model-all-cant-replace-it
         | 
| 19 | 
            -
                    context = where(nil)
         | 
| 20 | 
            -
                    context.slavery_target = name || :null_state
         | 
| 21 | 
            -
                    context
         | 
| 22 | 
            -
                  end
         | 
| 23 | 
            -
                end
         | 
| 24 | 
            -
              end
         | 
| 25 | 
            -
            end
         | 
| @@ -1,12 +0,0 @@ | |
| 1 | 
            -
            module ActiveRecord
         | 
| 2 | 
            -
              class LogSubscriber
         | 
| 3 | 
            -
             | 
| 4 | 
            -
                alias_method :debug_without_slavery, :debug
         | 
| 5 | 
            -
             | 
| 6 | 
            -
                def debug(msg)
         | 
| 7 | 
            -
                  db = Slavery.disabled ? "" : color("[#{Thread.current[:slavery] || "master"}]", ActiveSupport::LogSubscriber::GREEN, true)
         | 
| 8 | 
            -
                  debug_without_slavery(db + msg)
         | 
| 9 | 
            -
                end
         | 
| 10 | 
            -
             | 
| 11 | 
            -
              end
         | 
| 12 | 
            -
            end
         | 
| @@ -1,28 +0,0 @@ | |
| 1 | 
            -
            module ActiveRecord
         | 
| 2 | 
            -
              class Relation
         | 
| 3 | 
            -
                attr_accessor :slavery_target
         | 
| 4 | 
            -
             | 
| 5 | 
            -
                # Supports queries like User.on_slave.to_a
         | 
| 6 | 
            -
                alias_method :exec_queries_without_slavery, :exec_queries
         | 
| 7 | 
            -
             | 
| 8 | 
            -
                def exec_queries
         | 
| 9 | 
            -
                  if slavery_target
         | 
| 10 | 
            -
                    Slavery.on_slave(slavery_target) { exec_queries_without_slavery }
         | 
| 11 | 
            -
                  else
         | 
| 12 | 
            -
                    exec_queries_without_slavery
         | 
| 13 | 
            -
                  end
         | 
| 14 | 
            -
                end
         | 
| 15 | 
            -
             | 
| 16 | 
            -
             | 
| 17 | 
            -
                # Supports queries like User.on_slave.count
         | 
| 18 | 
            -
                alias_method :calculate_without_slavery, :calculate
         | 
| 19 | 
            -
             | 
| 20 | 
            -
                def calculate(*args)
         | 
| 21 | 
            -
                  if slavery_target
         | 
| 22 | 
            -
                    Slavery.on_slave(slavery_target) { calculate_without_slavery(*args) }
         | 
| 23 | 
            -
                  else
         | 
| 24 | 
            -
                    calculate_without_slavery(*args)
         | 
| 25 | 
            -
                  end
         | 
| 26 | 
            -
                end
         | 
| 27 | 
            -
              end
         | 
| 28 | 
            -
            end
         | 
    
        data/lib/slavery/base.rb
    DELETED
    
    | @@ -1,40 +0,0 @@ | |
| 1 | 
            -
            module Slavery
         | 
| 2 | 
            -
              class Base
         | 
| 3 | 
            -
                def initialize(target)
         | 
| 4 | 
            -
                  @target = decide_with(target)
         | 
| 5 | 
            -
                end
         | 
| 6 | 
            -
             | 
| 7 | 
            -
                def run(&block)
         | 
| 8 | 
            -
                  run_on @target, &block
         | 
| 9 | 
            -
                end
         | 
| 10 | 
            -
             | 
| 11 | 
            -
              private
         | 
| 12 | 
            -
             | 
| 13 | 
            -
                def decide_with(target)
         | 
| 14 | 
            -
                  if Slavery.disabled || target == :master
         | 
| 15 | 
            -
                    :master
         | 
| 16 | 
            -
                  elsif inside_transaction?
         | 
| 17 | 
            -
                    raise Slavery::Error.new('on_slave cannot be used inside transaction block!')
         | 
| 18 | 
            -
                  elsif target == :null_state
         | 
| 19 | 
            -
                    :slave
         | 
| 20 | 
            -
                  elsif target.present?
         | 
| 21 | 
            -
                    "slave_#{target}".to_sym
         | 
| 22 | 
            -
                  else
         | 
| 23 | 
            -
                    raise Slavery::Error.new('on_slave cannot be used with a nil target!')
         | 
| 24 | 
            -
                  end
         | 
| 25 | 
            -
                end
         | 
| 26 | 
            -
             | 
| 27 | 
            -
                def inside_transaction?
         | 
| 28 | 
            -
                  open_transactions = run_on(:master) { ActiveRecord::Base.connection.open_transactions }
         | 
| 29 | 
            -
                  open_transactions > Slavery::Transaction.base_depth
         | 
| 30 | 
            -
                end
         | 
| 31 | 
            -
             | 
| 32 | 
            -
                def run_on(target)
         | 
| 33 | 
            -
                  backup = Thread.current[:slavery] # Save for recursive nested calls
         | 
| 34 | 
            -
                  Thread.current[:slavery] = target
         | 
| 35 | 
            -
                  yield
         | 
| 36 | 
            -
                ensure
         | 
| 37 | 
            -
                  Thread.current[:slavery] = backup
         | 
| 38 | 
            -
                end
         | 
| 39 | 
            -
              end
         | 
| 40 | 
            -
            end
         | 
    
        data/lib/slavery/version.rb
    DELETED