activerecord-pgbouncer 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/.rspec +2 -0
- data/.travis.yml +4 -0
- data/Gemfile +9 -0
- data/LICENSE +23 -0
- data/README.md +30 -0
- data/Rakefile +6 -0
- data/activerecord-pgbouncer.gemspec +27 -0
- data/lib/active_record/connection_adapters/pgbouncer_adapter.rb +92 -0
- data/lib/active_record/pgbouncer.rb +3 -0
- data/lib/active_record/pgbouncer/version.rb +5 -0
- metadata +117 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: ec071fbf0fd88fead70eac5b4cd95852e81cc3e7
|
4
|
+
data.tar.gz: e3a2cd338297d973e1cb6e6ab1dbba4da140bc77
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: fa183c8b43fb46cdd6eeef003791878b17d461831dd839dca246302a3acf67752d03c62f9353d419678f66d16abe53f25824d499cd78c2732d5856032417766c
|
7
|
+
data.tar.gz: 1ebfee1542d62f54a1bbc936f67a27c737084c3a7cd07c19fda90a30e52422404c78c464cb3f3aa97585c701808d73571c4cb15a77bdc117c94ef00c4a80e7f3
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
Copyright (c) 2015, Remind101, Inc.
|
2
|
+
All rights reserved.
|
3
|
+
|
4
|
+
Redistribution and use in source and binary forms, with or without
|
5
|
+
modification, are permitted provided that the following conditions are met:
|
6
|
+
|
7
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
8
|
+
list of conditions and the following disclaimer.
|
9
|
+
|
10
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
11
|
+
this list of conditions and the following disclaimer in the documentation
|
12
|
+
and/or other materials provided with the distribution.
|
13
|
+
|
14
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
15
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
16
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
17
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
18
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
19
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
20
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
21
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
22
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
23
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
data/README.md
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# ActiveRecord PgBouncer Connection Adapter
|
2
|
+
|
3
|
+
When using PgBouncer, there are certain considerations to take into account:
|
4
|
+
|
5
|
+
* If you're using transaction pooling mode, prepared statements must be disabled.
|
6
|
+
* If you're using transaction pooling mode, session level features should not be used.
|
7
|
+
|
8
|
+
This is a light layer above the PostgreSQL connection adapter, that helps ensure that you don't make the mistakes above!
|
9
|
+
|
10
|
+
## Installation
|
11
|
+
|
12
|
+
Add this line to your application's Gemfile:
|
13
|
+
|
14
|
+
```ruby
|
15
|
+
gem 'activerecord-pgbouncer'
|
16
|
+
```
|
17
|
+
|
18
|
+
## Usage
|
19
|
+
|
20
|
+
This adds a `pgbouncer` adapter, which you can use in `config/database.yml` or `ENV['DATABASE_URL']`:
|
21
|
+
|
22
|
+
```yaml
|
23
|
+
production:
|
24
|
+
adapter: pgbouncer
|
25
|
+
pooling_mode: transaction # Can be `session`, `transaction`, or `statement`
|
26
|
+
```
|
27
|
+
|
28
|
+
```shell
|
29
|
+
export DATABASE_URL=pgbouncer://user:pass@host/db?pooling_mode=transaction
|
30
|
+
```
|
data/Rakefile
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'active_record/pgbouncer/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "activerecord-pgbouncer"
|
8
|
+
spec.version = ActiveRecord::PgBouncer::VERSION
|
9
|
+
spec.authors = ["Eric J. Holmes"]
|
10
|
+
spec.email = ["eric@remind101.com"]
|
11
|
+
|
12
|
+
spec.summary = %q{ActiveRecord connection adapter for safe PgBouncer use}
|
13
|
+
spec.description = %q{ActiveRecord connection adapter for safe PgBouncer use}
|
14
|
+
spec.homepage = "https://github.com/remind101/activerecord-pgbouncer"
|
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 "activerecord", [">= 4.1", "<= 5"]
|
23
|
+
|
24
|
+
spec.add_development_dependency "bundler", "~> 1.10"
|
25
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
26
|
+
spec.add_development_dependency "rspec"
|
27
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
require 'active_record/connection_adapters/postgresql_adapter'
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
# This is mostly copy pasta from https://github.com/rails/rails/blob/31ab3aa0e881acfd1475abae602455905a4cadf1/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb#L20-L42
|
5
|
+
module ConnectionHandling
|
6
|
+
VALID_PGBOUNCER_CONN_PARAMS = [:host, :hostaddr, :port, :dbname, :user, :password, :connect_timeout,
|
7
|
+
:client_encoding, :options, :application_name, :fallback_application_name,
|
8
|
+
:keepalives, :keepalives_idle, :keepalives_interval, :keepalives_count,
|
9
|
+
:tty, :sslmode, :requiressl, :sslcompression, :sslcert, :sslkey,
|
10
|
+
:sslrootcert, :sslcrl, :requirepeer, :krbsrvname, :gsslib, :service]
|
11
|
+
|
12
|
+
# Establishes a connection to the database that's used by all Active Record objects
|
13
|
+
def pgbouncer_connection(config)
|
14
|
+
pgbouncer = ConnectionAdapters::PgBouncerAdapter
|
15
|
+
|
16
|
+
conn_params = config.symbolize_keys
|
17
|
+
mode = conn_params[:pooling_mode]
|
18
|
+
|
19
|
+
raise "Unknown pooling mode provided: #{mode}" unless pgbouncer::POOLING_MODES.include?(mode)
|
20
|
+
disable_session = mode == pgbouncer::TRANSACTION_POOLING || mode == pgbouncer::STATEMENT_POOLING
|
21
|
+
raise "Prepared statements cannot be used with pgbouncer in #{mode} pooling mode" if disable_session && conn_params[:prepared_statements]
|
22
|
+
raise "Session level variables cannot be used with pgbouncer in #{mode} pooling mode" if disable_session && conn_params[:variables]
|
23
|
+
|
24
|
+
conn_params.delete_if { |_, v| v.nil? }
|
25
|
+
|
26
|
+
# Map ActiveRecords param names to PGs.
|
27
|
+
conn_params[:user] = conn_params.delete(:username) if conn_params[:username]
|
28
|
+
conn_params[:dbname] = conn_params.delete(:database) if conn_params[:database]
|
29
|
+
|
30
|
+
# Forward only valid config params to PGconn.connect.
|
31
|
+
conn_params.keep_if { |k, _| VALID_CONN_PARAMS.include?(k) }
|
32
|
+
|
33
|
+
# The postgres drivers don't allow the creation of an unconnected PGconn object,
|
34
|
+
# so just pass a nil connection object for the time being.
|
35
|
+
pgbouncer::new(mode, nil, logger, conn_params, config)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
module ActiveRecord
|
41
|
+
module ConnectionAdapters
|
42
|
+
class PgBouncerAdapter < PostgreSQLAdapter
|
43
|
+
# Most polite method. When client connects, a server connection will be
|
44
|
+
# assigned to it for the whole duration it stays connected. When client
|
45
|
+
# disconnects, the server connection will be put back into pool. This
|
46
|
+
# mode supports all PostgeSQL features.
|
47
|
+
SESSION_POOLING = 'session'.freeze
|
48
|
+
|
49
|
+
# Server connection is assigned to client only during a transaction. When
|
50
|
+
# PgBouncer notices that transaction is over, the server will be put back
|
51
|
+
# into pool. This mode breaks few session-based features of PostgreSQL.
|
52
|
+
# You can use it only when application cooperates by not using features
|
53
|
+
# that break. See the table below for incompatible features.
|
54
|
+
TRANSACTION_POOLING = 'transaction'.freeze
|
55
|
+
|
56
|
+
# Most aggressive method. This is transaction pooling with a twist -
|
57
|
+
# multi-statement transactions are disallowed. This is meant to enforce
|
58
|
+
# "autocommit" mode on client, mostly targeted for PL/Proxy.
|
59
|
+
STATEMENT_POOLING = 'statement'.freeze
|
60
|
+
|
61
|
+
POOLING_MODES = [SESSION_POOLING, TRANSACTION_POOLING, STATEMENT_POOLING]
|
62
|
+
|
63
|
+
attr_reader :pooling_mode
|
64
|
+
|
65
|
+
def initialize(pooling_mode, connection, logger, connection_parameters, config)
|
66
|
+
@pooling_mode = pooling_mode
|
67
|
+
super(connection, logger, connection_parameters, config)
|
68
|
+
end
|
69
|
+
|
70
|
+
# The PostgreSQL adapter sets a number of session level settings. In
|
71
|
+
# transaction pooling mode, this will have undesirable results, since
|
72
|
+
# each `SET` statement is not gauranteed to be executed with the same
|
73
|
+
# backend connection.
|
74
|
+
#
|
75
|
+
# Instead, when using this adapter, you should set a connect_query that sets the following:
|
76
|
+
#
|
77
|
+
# set client_encoding = 'UTF8'
|
78
|
+
# set client_min_messages = 'warning'
|
79
|
+
# set standard_conforming_strings = 'on'
|
80
|
+
# set timezone = 'UTC'
|
81
|
+
#
|
82
|
+
# See https://github.com/rails/rails/blob/a456acb2f2af8365eb9151c7cd2d5a10c189d191/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb#L648-L678
|
83
|
+
def configure_connection
|
84
|
+
if pooling_mode == TRANSACTION_POOLING || pooling_mode == STATEMENT_POOLING
|
85
|
+
# NOOP
|
86
|
+
else
|
87
|
+
super
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
metadata
ADDED
@@ -0,0 +1,117 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: activerecord-pgbouncer
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Eric J. Holmes
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-06-16 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: activerecord
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '4.1'
|
20
|
+
- - "<="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '5'
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '4.1'
|
30
|
+
- - "<="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '5'
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: bundler
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - "~>"
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '1.10'
|
40
|
+
type: :development
|
41
|
+
prerelease: false
|
42
|
+
version_requirements: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - "~>"
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '1.10'
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: rake
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - "~>"
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '10.0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - "~>"
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '10.0'
|
61
|
+
- !ruby/object:Gem::Dependency
|
62
|
+
name: rspec
|
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: ActiveRecord connection adapter for safe PgBouncer use
|
76
|
+
email:
|
77
|
+
- eric@remind101.com
|
78
|
+
executables: []
|
79
|
+
extensions: []
|
80
|
+
extra_rdoc_files: []
|
81
|
+
files:
|
82
|
+
- ".gitignore"
|
83
|
+
- ".rspec"
|
84
|
+
- ".travis.yml"
|
85
|
+
- Gemfile
|
86
|
+
- LICENSE
|
87
|
+
- README.md
|
88
|
+
- Rakefile
|
89
|
+
- activerecord-pgbouncer.gemspec
|
90
|
+
- lib/active_record/connection_adapters/pgbouncer_adapter.rb
|
91
|
+
- lib/active_record/pgbouncer.rb
|
92
|
+
- lib/active_record/pgbouncer/version.rb
|
93
|
+
homepage: https://github.com/remind101/activerecord-pgbouncer
|
94
|
+
licenses:
|
95
|
+
- MIT
|
96
|
+
metadata: {}
|
97
|
+
post_install_message:
|
98
|
+
rdoc_options: []
|
99
|
+
require_paths:
|
100
|
+
- lib
|
101
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
102
|
+
requirements:
|
103
|
+
- - ">="
|
104
|
+
- !ruby/object:Gem::Version
|
105
|
+
version: '0'
|
106
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
requirements: []
|
112
|
+
rubyforge_project:
|
113
|
+
rubygems_version: 2.4.5
|
114
|
+
signing_key:
|
115
|
+
specification_version: 4
|
116
|
+
summary: ActiveRecord connection adapter for safe PgBouncer use
|
117
|
+
test_files: []
|