active_replica 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +10 -0
- data/.rspec +2 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +9 -0
- data/CODE_OF_CONDUCT.md +13 -0
- data/Gemfile +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +46 -0
- data/Rakefile +1 -0
- data/active_replica.gemspec +28 -0
- data/bin/console +14 -0
- data/bin/setup +7 -0
- data/gemfiles/Gemfile.rails-4.2 +9 -0
- data/gemfiles/Gemfile.rails-5.0-beta +9 -0
- data/lib/active_replica.rb +49 -0
- data/lib/active_replica/connection_handler.rb +120 -0
- data/lib/active_replica/logging.rb +55 -0
- data/lib/active_replica/railtie.rb +17 -0
- data/lib/active_replica/runtime_registry.rb +19 -0
- data/lib/active_replica/version.rb +3 -0
- metadata +147 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 62270bf7218e6092a6784dc3bc70ca520408d72b
|
4
|
+
data.tar.gz: 3a76c3a4c55fdf265f00beb76eefed3b438d191d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 60b2681df0166bfdc6b0aa92e115f54ac95d10ad9f72d8f313d239042da67d783731e5687c5a8ee4acbc0b458f843e0707b971f5a75c68d23f1047d55b25a88f
|
7
|
+
data.tar.gz: d375463a1adf65a23177f8908abcf7674d1373fd5308846db4dc3166aba08c64cf5e5ae3bca74b4424c23ea0bafbd48dda6d38721f1e31cdc36b1dcc53023205
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.ruby-gemset
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
activereplica
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.2.2
|
data/.travis.yml
ADDED
data/CODE_OF_CONDUCT.md
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
# Contributor Code of Conduct
|
2
|
+
|
3
|
+
As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.
|
4
|
+
|
5
|
+
We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, age, or religion.
|
6
|
+
|
7
|
+
Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct.
|
8
|
+
|
9
|
+
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team.
|
10
|
+
|
11
|
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers.
|
12
|
+
|
13
|
+
This Code of Conduct is adapted from the [Contributor Covenant](http:contributor-covenant.org), version 1.0.0, available at [http://contributor-covenant.org/version/1/0/0/](http://contributor-covenant.org/version/1/0/0/)
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2015 GoGoTech
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
# ActiveReplica
|
2
|
+
|
3
|
+
[![Build Status](https://travis-ci.org/gogovan/active_replica.svg?branch=master)](https://travis-ci.org/gogovan/active_replica)
|
4
|
+
|
5
|
+
ActiveReplica makes it super-easy (and performant) to use a read-only replica with ActiveRecord
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'activereplica'
|
11
|
+
```
|
12
|
+
|
13
|
+
## Usage
|
14
|
+
|
15
|
+
```
|
16
|
+
# add named replicas
|
17
|
+
>> ActiveReplica.add_replica(:follower_1, adapter: "sqlite3", database: "replica1.sqlite")
|
18
|
+
>> ActiveReplica.add_replica(:follower_2, adapter: "sqlite3", database: "replica2.sqlite")
|
19
|
+
|
20
|
+
# get a list of replicas
|
21
|
+
>> ActiveReplica.replicas
|
22
|
+
=> [:follower_1, :follower_2]
|
23
|
+
|
24
|
+
# use a specified replica
|
25
|
+
>> ActiveReplica.with_replica(:follower_1) do
|
26
|
+
>> User.count
|
27
|
+
>> end
|
28
|
+
```
|
29
|
+
|
30
|
+
That's it
|
31
|
+
|
32
|
+
## Logging
|
33
|
+
|
34
|
+
Replica logging is not enabled by default.
|
35
|
+
|
36
|
+
If you want it, you can just require it.
|
37
|
+
|
38
|
+
```
|
39
|
+
require 'active_replica/logging'
|
40
|
+
```
|
41
|
+
|
42
|
+
Then your logs will get decorated.
|
43
|
+
|
44
|
+
```
|
45
|
+
[Replica: follower_1] (6.6ms) SELECT COUNT(*) FROM "users"
|
46
|
+
```
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'active_replica/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "active_replica"
|
8
|
+
spec.version = ActiveReplica::VERSION
|
9
|
+
spec.authors = ["Matthew Rudy Jacobs"]
|
10
|
+
spec.email = ["matthewrudyjacobs@gmail.com"]
|
11
|
+
|
12
|
+
spec.summary = %q{Simple, performant Read-Only replicas with ActiveRecord}
|
13
|
+
spec.description = %q{Add shards, and switch between them for key tasks}
|
14
|
+
spec.homepage = "https://github.com/gogovan/active_replica"
|
15
|
+
spec.license = "MIT"
|
16
|
+
|
17
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
18
|
+
spec.bindir = "exe"
|
19
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
20
|
+
spec.require_paths = ["lib"]
|
21
|
+
|
22
|
+
spec.add_dependency 'activesupport', '>= 4.2.0', '< 5.1.0'
|
23
|
+
spec.add_dependency 'activerecord', '>= 4.2.0', '< 5.1.0'
|
24
|
+
spec.add_dependency 'concurrent-ruby', '~> 1.0'
|
25
|
+
|
26
|
+
spec.add_development_dependency "bundler", "~> 1.9"
|
27
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
28
|
+
end
|
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "activereplica"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start
|
data/bin/setup
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'active_replica/version'
|
2
|
+
require 'active_replica/connection_handler'
|
3
|
+
require 'active_replica/railtie' if defined?(Rails)
|
4
|
+
require 'active_support/core_ext/module/attribute_accessors' # mattr_accessor
|
5
|
+
|
6
|
+
module ActiveReplica
|
7
|
+
mattr_accessor :connection_handler
|
8
|
+
|
9
|
+
def self.setup(active_record)
|
10
|
+
default_handler = active_record.default_connection_handler
|
11
|
+
active_handler = ActiveReplica::ConnectionHandler.new(default_handler)
|
12
|
+
self.connection_handler = active_handler
|
13
|
+
ActiveRecord::Base.default_connection_handler = active_handler
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.add_replica(name, config)
|
17
|
+
handler = handler_for_config(config)
|
18
|
+
self.connection_handler.add_shard(name, handler)
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.replicas
|
22
|
+
self.connection_handler.shards
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.active_replica
|
26
|
+
ActiveReplica::RuntimeRegistry.active_replica
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.with_replica(name)
|
30
|
+
before = ActiveReplica::RuntimeRegistry.active_replica
|
31
|
+
ActiveReplica::RuntimeRegistry.active_replica = name
|
32
|
+
self.connection_handler.with_shard(name) do
|
33
|
+
yield
|
34
|
+
end
|
35
|
+
ensure
|
36
|
+
ActiveReplica::RuntimeRegistry.active_replica = before
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.handler_for_config(config)
|
40
|
+
spec = spec_for_config(config)
|
41
|
+
ActiveRecord::ConnectionAdapters::ConnectionHandler.new.tap do |handler|
|
42
|
+
handler.establish_connection(ActiveRecord::Base, spec)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.spec_for_config(config)
|
47
|
+
ActiveRecord::ConnectionAdapters::ConnectionSpecification::Resolver.new("replica" => config).spec(:replica)
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,120 @@
|
|
1
|
+
require 'active_support/core_ext/module/delegation'
|
2
|
+
require 'active_replica/runtime_registry'
|
3
|
+
require 'concurrent'
|
4
|
+
|
5
|
+
module ActiveReplica
|
6
|
+
# This class works the same as the default ActiveRecord ConnectionHandler
|
7
|
+
# with each method carefully copied and delegated appropriately
|
8
|
+
#
|
9
|
+
# for single pool operations it delegates to the current active handler
|
10
|
+
# for operations over the whole connecton pool list, it delegates to each handler
|
11
|
+
#
|
12
|
+
class ConnectionHandler
|
13
|
+
def initialize(default_connection_handler)
|
14
|
+
@shard_to_connection_handler = Concurrent::Map.new(initial_capacity: 2)
|
15
|
+
@default_connection_handler = default_connection_handler
|
16
|
+
end
|
17
|
+
|
18
|
+
# easy failover to the default
|
19
|
+
attr_reader :default_connection_handler
|
20
|
+
|
21
|
+
# the key to the whole thing
|
22
|
+
# let us switch the active connection handler
|
23
|
+
#
|
24
|
+
private def active_connection_handler
|
25
|
+
ActiveReplica::RuntimeRegistry.connection_handler || default_connection_handler
|
26
|
+
end
|
27
|
+
|
28
|
+
private def active_connection_handler=(connection_handler)
|
29
|
+
ActiveReplica::RuntimeRegistry.connection_handler = connection_handler
|
30
|
+
end
|
31
|
+
|
32
|
+
# add a shard with connection handler
|
33
|
+
#
|
34
|
+
def add_shard(shard, connection_handler)
|
35
|
+
@shard_to_connection_handler[shard] = connection_handler
|
36
|
+
end
|
37
|
+
|
38
|
+
# get the list of shard names
|
39
|
+
#
|
40
|
+
def shards
|
41
|
+
@shard_to_connection_handler.keys
|
42
|
+
end
|
43
|
+
|
44
|
+
# get the shard with the connection handler
|
45
|
+
#
|
46
|
+
def get_shard(shard)
|
47
|
+
@shard_to_connection_handler[shard] or fail "no handler for shard #{shard.inspect}"
|
48
|
+
end
|
49
|
+
|
50
|
+
# fetch the shard and use it
|
51
|
+
#
|
52
|
+
def with_shard(shard)
|
53
|
+
connection_handler = get_shard(shard)
|
54
|
+
with_connection_handler(connection_handler) do
|
55
|
+
yield
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# switch the handler for the current thread
|
60
|
+
# and ensure its put back at the end
|
61
|
+
#
|
62
|
+
def with_connection_handler(connection_handler)
|
63
|
+
before = active_connection_handler
|
64
|
+
self.active_connection_handler = connection_handler
|
65
|
+
yield
|
66
|
+
ensure
|
67
|
+
self.active_connection_handler = before
|
68
|
+
end
|
69
|
+
|
70
|
+
# grab the full list of connection handlers
|
71
|
+
# to enable clean up methods
|
72
|
+
#
|
73
|
+
private def connection_handler_list
|
74
|
+
@shard_to_connection_handler.values + [default_connection_handler].compact
|
75
|
+
end
|
76
|
+
|
77
|
+
# the connection pool list is used for various cleaning tasks
|
78
|
+
# it should be modified to return the full list
|
79
|
+
# mapped over all children
|
80
|
+
#
|
81
|
+
def connection_pool_list
|
82
|
+
connection_handler_list.flat_map(&:connection_pool_list)
|
83
|
+
end
|
84
|
+
alias :connection_pools :connection_pool_list
|
85
|
+
|
86
|
+
# delegate establishing a connection to the active handler
|
87
|
+
#
|
88
|
+
delegate :establish_connection,
|
89
|
+
to: :active_connection_handler
|
90
|
+
|
91
|
+
# the active connection method should just delegate
|
92
|
+
#
|
93
|
+
def active_connections?
|
94
|
+
connection_handler_list.any?(&:active_connections)
|
95
|
+
end
|
96
|
+
|
97
|
+
# the clear connection methods can be delegated to each connection handler
|
98
|
+
#
|
99
|
+
def clear_active_connections!
|
100
|
+
connection_handler_list.each(&:clear_active_connections!)
|
101
|
+
end
|
102
|
+
|
103
|
+
def clear_reloadable_connections!
|
104
|
+
connection_handler_list.each(&:clear_reloadable_connections!)
|
105
|
+
end
|
106
|
+
|
107
|
+
def clear_all_connections!
|
108
|
+
connection_handler_list.each(&:clear_all_connections!)
|
109
|
+
end
|
110
|
+
|
111
|
+
# individual handler methods
|
112
|
+
# we should just delegate to the active handler
|
113
|
+
#
|
114
|
+
delegate :retrieve_connection,
|
115
|
+
:connected?,
|
116
|
+
:remove_connection,
|
117
|
+
:retrieve_connection_pool,
|
118
|
+
to: :active_connection_handler
|
119
|
+
end
|
120
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# Implementation courtesy of db-charmer.
|
2
|
+
# Via Octopus
|
3
|
+
module ActiveReplica
|
4
|
+
module AdapterExtension
|
5
|
+
class InstrumenterDecorator < BasicObject
|
6
|
+
def initialize(adapter, instrumenter)
|
7
|
+
@adapter = adapter
|
8
|
+
@instrumenter = instrumenter
|
9
|
+
end
|
10
|
+
|
11
|
+
def instrument(name, payload = {}, &block)
|
12
|
+
payload[:active_replica] = ::ActiveReplica.active_replica
|
13
|
+
@instrumenter.instrument(name, payload, &block)
|
14
|
+
end
|
15
|
+
|
16
|
+
def method_missing(meth, *args, &block)
|
17
|
+
@instrumenter.send(meth, *args, &block)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.included(base)
|
22
|
+
base.alias_method_chain :initialize, :active_replica
|
23
|
+
end
|
24
|
+
|
25
|
+
def active_replica
|
26
|
+
@config[:active_replica]
|
27
|
+
end
|
28
|
+
|
29
|
+
def initialize_with_active_replica(*args)
|
30
|
+
initialize_without_active_replica(*args)
|
31
|
+
@instrumenter = InstrumenterDecorator.new(self, @instrumenter)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
module LogSubscriber
|
36
|
+
def self.included(base)
|
37
|
+
base.send(:attr_accessor, :active_replica)
|
38
|
+
base.alias_method_chain :sql, :active_replica
|
39
|
+
base.alias_method_chain :debug, :active_replica
|
40
|
+
end
|
41
|
+
|
42
|
+
def sql_with_active_replica(event)
|
43
|
+
self.active_replica = event.payload[:active_replica]
|
44
|
+
sql_without_active_replica(event)
|
45
|
+
end
|
46
|
+
|
47
|
+
def debug_with_active_replica(msg)
|
48
|
+
conn = active_replica ? color("[Replica: #{active_replica}]", ActiveSupport::LogSubscriber::GREEN, true) : ''
|
49
|
+
debug_without_active_replica(conn + msg)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
ActiveRecord::LogSubscriber.send(:include, ActiveReplica::LogSubscriber)
|
55
|
+
ActiveRecord::ConnectionAdapters::AbstractAdapter.send(:include, ActiveReplica::AdapterExtension)
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'active_replica'
|
2
|
+
|
3
|
+
begin
|
4
|
+
require 'rails/railtie'
|
5
|
+
|
6
|
+
module ActiveReplica
|
7
|
+
class Railtie < Rails::Railtie # :nodoc:
|
8
|
+
initializer 'active_replica.initialize' do
|
9
|
+
ActiveSupport.on_load(:active_record) do
|
10
|
+
ActiveReplica.setup(ActiveRecord::Base)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
rescue LoadError
|
16
|
+
warn "can't load railtie"
|
17
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'active_support/per_thread_registry'
|
2
|
+
|
3
|
+
module ActiveReplica
|
4
|
+
# This is a thread locals registry for ActiveReplica.
|
5
|
+
#
|
6
|
+
# Taken from ActiveRecord's equivalent
|
7
|
+
# we use it to switch and access the connection_handler
|
8
|
+
#
|
9
|
+
class RuntimeRegistry # :nodoc:
|
10
|
+
extend ActiveSupport::PerThreadRegistry
|
11
|
+
|
12
|
+
attr_accessor :active_replica, :connection_handler
|
13
|
+
|
14
|
+
[:active_replica, :connection_handler].each do |val|
|
15
|
+
class_eval %{ def self.#{val}; instance.#{val}; end }, __FILE__, __LINE__
|
16
|
+
class_eval %{ def self.#{val}=(x); instance.#{val}=x; end }, __FILE__, __LINE__
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
metadata
ADDED
@@ -0,0 +1,147 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: active_replica
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Matthew Rudy Jacobs
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-12-21 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: activesupport
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 4.2.0
|
20
|
+
- - "<"
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 5.1.0
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 4.2.0
|
30
|
+
- - "<"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 5.1.0
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: activerecord
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - ">="
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: 4.2.0
|
40
|
+
- - "<"
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: 5.1.0
|
43
|
+
type: :runtime
|
44
|
+
prerelease: false
|
45
|
+
version_requirements: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - ">="
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: 4.2.0
|
50
|
+
- - "<"
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: 5.1.0
|
53
|
+
- !ruby/object:Gem::Dependency
|
54
|
+
name: concurrent-ruby
|
55
|
+
requirement: !ruby/object:Gem::Requirement
|
56
|
+
requirements:
|
57
|
+
- - "~>"
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: '1.0'
|
60
|
+
type: :runtime
|
61
|
+
prerelease: false
|
62
|
+
version_requirements: !ruby/object:Gem::Requirement
|
63
|
+
requirements:
|
64
|
+
- - "~>"
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: '1.0'
|
67
|
+
- !ruby/object:Gem::Dependency
|
68
|
+
name: bundler
|
69
|
+
requirement: !ruby/object:Gem::Requirement
|
70
|
+
requirements:
|
71
|
+
- - "~>"
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: '1.9'
|
74
|
+
type: :development
|
75
|
+
prerelease: false
|
76
|
+
version_requirements: !ruby/object:Gem::Requirement
|
77
|
+
requirements:
|
78
|
+
- - "~>"
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: '1.9'
|
81
|
+
- !ruby/object:Gem::Dependency
|
82
|
+
name: rake
|
83
|
+
requirement: !ruby/object:Gem::Requirement
|
84
|
+
requirements:
|
85
|
+
- - "~>"
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: '10.0'
|
88
|
+
type: :development
|
89
|
+
prerelease: false
|
90
|
+
version_requirements: !ruby/object:Gem::Requirement
|
91
|
+
requirements:
|
92
|
+
- - "~>"
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: '10.0'
|
95
|
+
description: Add shards, and switch between them for key tasks
|
96
|
+
email:
|
97
|
+
- matthewrudyjacobs@gmail.com
|
98
|
+
executables: []
|
99
|
+
extensions: []
|
100
|
+
extra_rdoc_files: []
|
101
|
+
files:
|
102
|
+
- ".gitignore"
|
103
|
+
- ".rspec"
|
104
|
+
- ".ruby-gemset"
|
105
|
+
- ".ruby-version"
|
106
|
+
- ".travis.yml"
|
107
|
+
- CODE_OF_CONDUCT.md
|
108
|
+
- Gemfile
|
109
|
+
- LICENSE.txt
|
110
|
+
- README.md
|
111
|
+
- Rakefile
|
112
|
+
- active_replica.gemspec
|
113
|
+
- bin/console
|
114
|
+
- bin/setup
|
115
|
+
- gemfiles/Gemfile.rails-4.2
|
116
|
+
- gemfiles/Gemfile.rails-5.0-beta
|
117
|
+
- lib/active_replica.rb
|
118
|
+
- lib/active_replica/connection_handler.rb
|
119
|
+
- lib/active_replica/logging.rb
|
120
|
+
- lib/active_replica/railtie.rb
|
121
|
+
- lib/active_replica/runtime_registry.rb
|
122
|
+
- lib/active_replica/version.rb
|
123
|
+
homepage: https://github.com/gogovan/active_replica
|
124
|
+
licenses:
|
125
|
+
- MIT
|
126
|
+
metadata: {}
|
127
|
+
post_install_message:
|
128
|
+
rdoc_options: []
|
129
|
+
require_paths:
|
130
|
+
- lib
|
131
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
132
|
+
requirements:
|
133
|
+
- - ">="
|
134
|
+
- !ruby/object:Gem::Version
|
135
|
+
version: '0'
|
136
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
137
|
+
requirements:
|
138
|
+
- - ">="
|
139
|
+
- !ruby/object:Gem::Version
|
140
|
+
version: '0'
|
141
|
+
requirements: []
|
142
|
+
rubyforge_project:
|
143
|
+
rubygems_version: 2.4.8
|
144
|
+
signing_key:
|
145
|
+
specification_version: 4
|
146
|
+
summary: Simple, performant Read-Only replicas with ActiveRecord
|
147
|
+
test_files: []
|