postamt 0.9.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 +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:
|