activerecord-pgbouncer 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.2.2
4
+ before_install: gem install bundler -v 1.10.4
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in activerecord-pgbouncer.gemspec
4
+ gemspec
5
+
6
+ group :development, :test do
7
+ gem 'activerecord', '4.1.14'
8
+ gem 'pg'
9
+ end
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,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -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
@@ -0,0 +1,3 @@
1
+ require 'active_record'
2
+ require 'active_record/pgbouncer/version'
3
+ require 'active_record/connection_adapters/pgbouncer_adapter'
@@ -0,0 +1,5 @@
1
+ module ActiveRecord
2
+ module PgBouncer
3
+ VERSION = "0.1.0"
4
+ end
5
+ 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: []