postamt 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +90 -0
- data/Rakefile +1 -0
- data/lib/postamt.rb +118 -0
- data/lib/postamt/connection_handler.rb +124 -0
- data/lib/postamt/railtie.rb +21 -0
- data/lib/postamt/version.rb +3 -0
- data/postamt.gemspec +25 -0
- metadata +119 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 34ca7a878f7cd7eb35c89e13148ff5bcc1ee9902
|
4
|
+
data.tar.gz: 019233a57d48dcddfefd6ea65025e4a98d59ee78
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 40034cd7b4e0016401f4a98893b2e70a48556a340b9fe541e7693369eb039ea02f1e1c104ec9a81bb2a0b6becbb0e53f06fa1af3145ce4b993eb9bd4c348258b
|
7
|
+
data.tar.gz: 2f7f090a657609cd192b44add07d8dd28e88773d299f6e8f792500f62f997d9917dfee86fa0192e2128f54381d6b126a108902a141919786169896c98cc87b55
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Martin Schürrer
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
# Postamt
|
2
|
+
|
3
|
+
Performs (some of) your read-only queries on a hot standby.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'pg_charmer'
|
10
|
+
|
11
|
+
## Example usage
|
12
|
+
|
13
|
+
```yaml
|
14
|
+
# database.yml
|
15
|
+
development:
|
16
|
+
adapter: postgresql
|
17
|
+
database: app
|
18
|
+
username: app
|
19
|
+
password:
|
20
|
+
host: master.db.internal
|
21
|
+
encoding: utf8
|
22
|
+
slave:
|
23
|
+
host: slave.db.internal
|
24
|
+
username: app_readonly
|
25
|
+
```
|
26
|
+
|
27
|
+
```ruby
|
28
|
+
class UserController < ApplicationController
|
29
|
+
use_db_connection :slave, for: ['User'], only: [:search]
|
30
|
+
|
31
|
+
def search
|
32
|
+
# SELECTs here are sent to slave
|
33
|
+
# User#save and User.create would be sent to master anyways.
|
34
|
+
# Everything in a transaction block too.
|
35
|
+
@users = User.where(...) # sent to slave
|
36
|
+
@something_else = SomethingElse.first # sent to master
|
37
|
+
end
|
38
|
+
|
39
|
+
def create
|
40
|
+
@user = User.new(params[:user])
|
41
|
+
@user.save! # sent to master
|
42
|
+
end
|
43
|
+
|
44
|
+
def invoice
|
45
|
+
transaction do
|
46
|
+
@user = User.where(...) # sent to master
|
47
|
+
@invoices = Invoice.create(...) # sent to master
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
```
|
52
|
+
|
53
|
+
```ruby
|
54
|
+
class ArchivedItem < ActiveRecord::Base
|
55
|
+
# default_connection can be overwritten with
|
56
|
+
# * Postamt.on(...) { ... },
|
57
|
+
# * ActiveRecord::Base.transaction { ... }, and
|
58
|
+
# * use_db_connection :other_connection, for: ['ArchivedItem'] in a controller.
|
59
|
+
self.default_connection = :slave
|
60
|
+
end
|
61
|
+
|
62
|
+
User.where(...) # sent to master
|
63
|
+
item = ArchivedItem.where(...) # sent to slave
|
64
|
+
item.title = "changed title"
|
65
|
+
item.save! # sent to master
|
66
|
+
item.reload # sent to slave, beware of replication lag here!
|
67
|
+
|
68
|
+
ActiveRecord::Base.transaction do
|
69
|
+
ArchivedItem.where(...) # sent to master, since we're in a transaction
|
70
|
+
User.where(...) # sent to master
|
71
|
+
end
|
72
|
+
|
73
|
+
Postamt.on(:master) do
|
74
|
+
ArchivedItem.where(...) # sent to master
|
75
|
+
User.where(...) # sent to master
|
76
|
+
end
|
77
|
+
```
|
78
|
+
|
79
|
+
```ruby
|
80
|
+
# If you don't want to test with a slave DB put this in config/environments/test.rb
|
81
|
+
Postamt.force_connection = :master
|
82
|
+
```
|
83
|
+
|
84
|
+
## Contributing
|
85
|
+
|
86
|
+
1. Fork it
|
87
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
88
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
89
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
90
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/lib/postamt.rb
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
require 'action_controller'
|
2
|
+
require 'active_record'
|
3
|
+
require 'postamt/connection_handler'
|
4
|
+
require 'postamt/railtie'
|
5
|
+
|
6
|
+
module Postamt
|
7
|
+
mattr_accessor :default_connection
|
8
|
+
mattr_accessor :transaction_connection
|
9
|
+
mattr_accessor :force_connection
|
10
|
+
|
11
|
+
# Setup defaults
|
12
|
+
self.default_connection = :master
|
13
|
+
self.transaction_connection = :master
|
14
|
+
self.force_connection = nil
|
15
|
+
|
16
|
+
def self.on(connection)
|
17
|
+
self.connection_stack << connection
|
18
|
+
begin
|
19
|
+
yield
|
20
|
+
ensure
|
21
|
+
self.connection_stack.pop
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.configurations
|
26
|
+
@configurations ||= begin
|
27
|
+
input = ActiveRecord::Base.configurations[Rails.env]
|
28
|
+
configs = input.select { |k, v| v.is_a? Hash }
|
29
|
+
master_config = input.reject { |k, v| v.is_a? Hash }
|
30
|
+
configs.each { |k, v| v.reverse_merge!(master_config) }
|
31
|
+
configs['master'] = master_config
|
32
|
+
configs
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.connection_stack
|
37
|
+
Thread.current[:postamt_connection_stack] ||= []
|
38
|
+
end
|
39
|
+
|
40
|
+
# Used by use_db_connection. Cleared in an after_filter.
|
41
|
+
def self.overwritten_default_connections
|
42
|
+
Thread.current[:postamt_overwritten_default_connections] ||= {}
|
43
|
+
end
|
44
|
+
|
45
|
+
if Rails::VERSION::MAJOR == 4 and Rails::VERSION::MINOR == 0
|
46
|
+
Postamt::ConnectionSpecificationResolver = ActiveRecord::ConnectionAdapters::ConnectionSpecification::Resolver
|
47
|
+
elsif Rails::VERSION::MAJOR == 3 and Rails::VERSION::MINOR == 2
|
48
|
+
Postamt::ConnectionSpecificationResolver = ActiveRecord::Base::ConnectionSpecification::Resolver
|
49
|
+
else
|
50
|
+
abort "Postamt doesn't support Rails version #{Rails.version}"
|
51
|
+
end
|
52
|
+
|
53
|
+
# Called by Postamt::Railtie
|
54
|
+
def self.hook!
|
55
|
+
if Rails::VERSION::MAJOR == 4 and Rails::VERSION::MINOR == 0
|
56
|
+
ActiveRecord::Base.default_connection_handler = Postamt::ConnectionHandler.new
|
57
|
+
elsif Rails::VERSION::MAJOR == 3 and Rails::VERSION::MINOR == 2
|
58
|
+
ActiveRecord::Base.connection_handler = Postamt::ConnectionHandler.new
|
59
|
+
end
|
60
|
+
|
61
|
+
ActiveRecord::Base.instance_eval do
|
62
|
+
class_attribute :default_connection
|
63
|
+
|
64
|
+
# disable Model.establish_connection
|
65
|
+
def establish_connection(*args)
|
66
|
+
# This would be the only place Model.connection_handler.establish_connection is called.
|
67
|
+
nil
|
68
|
+
end
|
69
|
+
|
70
|
+
# a transaction runs on Postamt.transaction_connection or on the :on option
|
71
|
+
def transaction(options = {}, &block)
|
72
|
+
if connection = (options.delete(:on) || Postamt.transaction_connection)
|
73
|
+
Postamt.on(connection) { super }
|
74
|
+
else
|
75
|
+
super
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
ActiveRecord::Relation.class_eval do
|
81
|
+
# Also make sure that actions that don't instantiate the model and
|
82
|
+
# therefore don't call #save or #destroy run on master.
|
83
|
+
# update_column calls update_all, delete calls delete_all, so we don't
|
84
|
+
# have to monkey patch them.
|
85
|
+
|
86
|
+
def delete_all_with_postamt(conditions = nil)
|
87
|
+
Postamt.on(:master) { delete_all_without_postamt(conditions) }
|
88
|
+
end
|
89
|
+
|
90
|
+
def update_all_with_postamt(updates, conditions = nil, options = {})
|
91
|
+
Postamt.on(:master) { update_all_without_postamt(updates, conditions, options) }
|
92
|
+
end
|
93
|
+
|
94
|
+
# TODO: Switch to Module#prepend once we are Ruby-2.0.0-only
|
95
|
+
alias_method_chain :delete_all, :postamt
|
96
|
+
alias_method_chain :update_all, :postamt
|
97
|
+
end
|
98
|
+
|
99
|
+
ActionController::Base.instance_eval do
|
100
|
+
def use_db_connection(connection, args)
|
101
|
+
default_connections = {}
|
102
|
+
klass_names = args.delete(:for)
|
103
|
+
klass_names.each do |klass_name|
|
104
|
+
default_connections[klass_name] = connection
|
105
|
+
end
|
106
|
+
|
107
|
+
before_filter(args) do |controller|
|
108
|
+
Postamt.overwritten_default_connections.merge!(default_connections)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
after_filter do
|
113
|
+
Postamt.overwritten_default_connections.clear
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
@@ -0,0 +1,124 @@
|
|
1
|
+
require 'atomic'
|
2
|
+
require 'thread_safe'
|
3
|
+
|
4
|
+
module Postamt
|
5
|
+
class ConnectionHandler
|
6
|
+
def initialize
|
7
|
+
@process_pid = Atomic.new(nil)
|
8
|
+
end
|
9
|
+
|
10
|
+
def connection_pools
|
11
|
+
# See https://github.com/rails/rails/commit/c3ca7ac09e960fa1287adc730e8ddc713e844c37
|
12
|
+
Hash[self.connection_pool_list.map { |pool| [pool.spec, pool] }]
|
13
|
+
end
|
14
|
+
|
15
|
+
def connection_pool_list
|
16
|
+
self.ensure_ready
|
17
|
+
@pools.values
|
18
|
+
end
|
19
|
+
|
20
|
+
# Returns true if there are any active connections among the connection
|
21
|
+
# pools that the ConnectionHandler is managing.
|
22
|
+
def active_connections?
|
23
|
+
self.ensure_ready
|
24
|
+
self.connection_pool_list.any?(&:active_connection?)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Returns any connections in use by the current thread back to the pool,
|
28
|
+
# and also returns connections to the pool cached by threads that are no
|
29
|
+
# longer alive.
|
30
|
+
def clear_active_connections!
|
31
|
+
self.ensure_ready
|
32
|
+
self.connection_pool_list.each(&:release_connection)
|
33
|
+
end
|
34
|
+
|
35
|
+
# Clears the cache which maps classes.
|
36
|
+
def clear_reloadable_connections!
|
37
|
+
self.ensure_ready
|
38
|
+
self.connection_pool_list.each(&:clear_reloadable_connections!)
|
39
|
+
end
|
40
|
+
|
41
|
+
def clear_all_connections!
|
42
|
+
self.ensure_ready
|
43
|
+
self.connection_pool_list.each(&:disconnect!)
|
44
|
+
end
|
45
|
+
|
46
|
+
# Locate the connection of the nearest super class. This can be an
|
47
|
+
# active or defined connection: if it is the latter, it will be
|
48
|
+
# opened and set as the active connection for the class it was defined
|
49
|
+
# for (not necessarily the current class).
|
50
|
+
def retrieve_connection(klass) #:nodoc:
|
51
|
+
self.ensure_ready
|
52
|
+
pool = self.retrieve_connection_pool(klass)
|
53
|
+
(pool && pool.connection) or raise ActiveRecord::ConnectionNotEstablished
|
54
|
+
end
|
55
|
+
|
56
|
+
# Returns true if a connection that's accessible to this class has
|
57
|
+
# already been opened.
|
58
|
+
def connected?(klass)
|
59
|
+
return false if Process.pid != @process_pid.get
|
60
|
+
conn = self.retrieve_connection_pool(klass)
|
61
|
+
conn && conn.connected?
|
62
|
+
end
|
63
|
+
|
64
|
+
# Only called in ActiveRecord test code, so performance isn't an issue.
|
65
|
+
def remove_connection(owner)
|
66
|
+
self.clear_cache
|
67
|
+
# Don't return a ConnectionSpecification hash since we've disabled establish_connection anyway
|
68
|
+
return nil
|
69
|
+
end
|
70
|
+
|
71
|
+
# Called by ActiveRecord::ConnectionHandling#connection_pool.
|
72
|
+
def retrieve_connection_pool(klass)
|
73
|
+
self.ensure_ready
|
74
|
+
self.pool_for(klass)
|
75
|
+
end
|
76
|
+
|
77
|
+
protected
|
78
|
+
|
79
|
+
def prepare
|
80
|
+
@process_pid.set(Process.pid)
|
81
|
+
@pools = ThreadSafe::Cache.new(initial_capacity: 2)
|
82
|
+
end
|
83
|
+
|
84
|
+
def ensure_ready
|
85
|
+
if Process.pid != @process_pid.get
|
86
|
+
# We've been forked -> throw away connection pools
|
87
|
+
prepare
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
# Throw away all pools on next request
|
92
|
+
def clear_cache
|
93
|
+
@process_pid.set(nil)
|
94
|
+
end
|
95
|
+
|
96
|
+
def connection_for(klass)
|
97
|
+
Postamt.force_connection || Postamt.connection_stack.last || Postamt.overwritten_default_connections[klass.name] || klass.default_connection || Postamt.default_connection
|
98
|
+
end
|
99
|
+
|
100
|
+
def pool_for(klass)
|
101
|
+
# Sauspiel's reportable dependency makes Rails 3.2 request a connection early,
|
102
|
+
# before the App is initialized. Return nil in that case, Rails deals with that
|
103
|
+
return nil if ActiveRecord::Base.configurations[Rails.env].nil?
|
104
|
+
|
105
|
+
connection = connection_for(klass)
|
106
|
+
# Ideally we would use #fetch here, as class_to_pool[klass] may sometimes be nil.
|
107
|
+
# However, benchmarking (https://gist.github.com/jonleighton/3552829) showed that
|
108
|
+
# #fetch is significantly slower than #[]. So in the nil case, no caching will
|
109
|
+
# take place, but that's ok since the nil case is not the common one that we wish
|
110
|
+
# to optimise for.
|
111
|
+
@pools[connection] ||= begin
|
112
|
+
Postamt.configurations[connection.to_s] ||= Postamt.configurations['master']
|
113
|
+
resolver = Postamt::ConnectionSpecificationResolver.new connection, Postamt.configurations
|
114
|
+
spec = resolver.spec
|
115
|
+
|
116
|
+
unless ActiveRecord::Base.respond_to?(spec.adapter_method)
|
117
|
+
raise ActiveRecord::AdapterNotFound, "database configuration specifies nonexistent #{spec.config[:adapter]} adapter"
|
118
|
+
end
|
119
|
+
|
120
|
+
ActiveRecord::ConnectionAdapters::ConnectionPool.new(spec)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Postamt
|
2
|
+
class Railtie < Rails::Railtie
|
3
|
+
railtie_name "postamt"
|
4
|
+
|
5
|
+
initializer "postamt.hook", before: "active_record.initialize_database" do |app|
|
6
|
+
if (defined?($rails_rake_task) && $rails_rake_task)
|
7
|
+
# We mustn't hook into AR when db:migrate or db:test:load_schema
|
8
|
+
# run, but user-defined Rake tasks still need us
|
9
|
+
task_names = []
|
10
|
+
tasks_to_examine = Rake.application.top_level_tasks.map{ |task_name| Rake.application[task_name] }
|
11
|
+
until tasks_to_examine.empty?
|
12
|
+
task = tasks_to_examine.pop
|
13
|
+
task_names << task.name
|
14
|
+
tasks_to_examine += task.prerequisite_tasks
|
15
|
+
end
|
16
|
+
next if task_names.any? { |task_name| task_name.start_with? "db:" }
|
17
|
+
end
|
18
|
+
Postamt.hook!
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/postamt.gemspec
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'postamt/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "postamt"
|
8
|
+
spec.version = Postamt::VERSION
|
9
|
+
spec.authors = ["Martin Schürrer"]
|
10
|
+
spec.email = ["martin@schuerrer.org"]
|
11
|
+
spec.description = %q{Choose per model and/or controller&action whether a read-only query should be sent to master or a hot standby. Or just use Postamt.on(:slave) { ... }. }
|
12
|
+
spec.summary = %q{Performs (some of) your read-only queries on a hot standby}
|
13
|
+
spec.homepage = "https://github.com/sauspiel/postamt"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/).reject { |f| f.start_with? 'testapp' }
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_dependency "thread_safe", "~> 0.1"
|
22
|
+
spec.add_dependency "railties", [">= 3.2.0", "< 4.1.0"]
|
23
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
24
|
+
spec.add_development_dependency "rake"
|
25
|
+
end
|
metadata
ADDED
@@ -0,0 +1,119 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: postamt
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.9.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Martin Schürrer
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-04-16 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: thread_safe
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0.1'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0.1'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: railties
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 3.2.0
|
34
|
+
- - <
|
35
|
+
- !ruby/object:Gem::Version
|
36
|
+
version: 4.1.0
|
37
|
+
type: :runtime
|
38
|
+
prerelease: false
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 3.2.0
|
44
|
+
- - <
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: 4.1.0
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: bundler
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ~>
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '1.3'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - ~>
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '1.3'
|
61
|
+
- !ruby/object:Gem::Dependency
|
62
|
+
name: rake
|
63
|
+
requirement: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - '>='
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '0'
|
68
|
+
type: :development
|
69
|
+
prerelease: false
|
70
|
+
version_requirements: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - '>='
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '0'
|
75
|
+
description: 'Choose per model and/or controller&action whether a read-only query
|
76
|
+
should be sent to master or a hot standby. Or just use Postamt.on(:slave) { ...
|
77
|
+
}. '
|
78
|
+
email:
|
79
|
+
- martin@schuerrer.org
|
80
|
+
executables: []
|
81
|
+
extensions: []
|
82
|
+
extra_rdoc_files: []
|
83
|
+
files:
|
84
|
+
- .gitignore
|
85
|
+
- Gemfile
|
86
|
+
- LICENSE.txt
|
87
|
+
- README.md
|
88
|
+
- Rakefile
|
89
|
+
- lib/postamt.rb
|
90
|
+
- lib/postamt/connection_handler.rb
|
91
|
+
- lib/postamt/railtie.rb
|
92
|
+
- lib/postamt/version.rb
|
93
|
+
- postamt.gemspec
|
94
|
+
homepage: https://github.com/sauspiel/postamt
|
95
|
+
licenses:
|
96
|
+
- MIT
|
97
|
+
metadata: {}
|
98
|
+
post_install_message:
|
99
|
+
rdoc_options: []
|
100
|
+
require_paths:
|
101
|
+
- lib
|
102
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
103
|
+
requirements:
|
104
|
+
- - '>='
|
105
|
+
- !ruby/object:Gem::Version
|
106
|
+
version: '0'
|
107
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
108
|
+
requirements:
|
109
|
+
- - '>='
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
version: '0'
|
112
|
+
requirements: []
|
113
|
+
rubyforge_project:
|
114
|
+
rubygems_version: 2.0.3
|
115
|
+
signing_key:
|
116
|
+
specification_version: 4
|
117
|
+
summary: Performs (some of) your read-only queries on a hot standby
|
118
|
+
test_files: []
|
119
|
+
has_rdoc:
|